diff --git a/event-asynchronous/README.md b/event-asynchronous/README.md
new file mode 100644
index 000000000..ef35d0b38
--- /dev/null
+++ b/event-asynchronous/README.md
@@ -0,0 +1,30 @@
+---
+layout: pattern
+title: Event-based Asynchronous
+folder: event-asynchronous
+permalink: /patterns/event-asynchronous/
+categories: Concurrency
+tags:
+ - difficulty-intermediate
+ - performance
+ - Java
+---
+
+## Intent
+The Event-based Asynchronous Pattern makes available the advantages of multithreaded applications while hiding many
+of the complex issues inherent in multithreaded design. Using a class that supports this pattern can allow you to:-
+(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.
+
+
+
+## Applicability
+Use the Event-based Asynchronous pattern(s) when
+
+* Time-consuming tasks are needed to run in the background without disrupting the current application.
+
+## Credits
+
+* [Event-based Asynchronous Pattern Overview](https://msdn.microsoft.com/en-us/library/wewwczdw%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396)
diff --git a/event-asynchronous/etc/event-asynchronous.png b/event-asynchronous/etc/event-asynchronous.png
new file mode 100644
index 000000000..a46ffe1c5
Binary files /dev/null and b/event-asynchronous/etc/event-asynchronous.png differ
diff --git a/event-asynchronous/etc/event-asynchronous.ucls b/event-asynchronous/etc/event-asynchronous.ucls
new file mode 100644
index 000000000..df09fc28d
--- /dev/null
+++ b/event-asynchronous/etc/event-asynchronous.ucls
@@ -0,0 +1,118 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/event-asynchronous/pom.xml b/event-asynchronous/pom.xml
new file mode 100644
index 000000000..1bc4549d4
--- /dev/null
+++ b/event-asynchronous/pom.xml
@@ -0,0 +1,42 @@
+
+
+
+ 4.0.0
+
+ com.iluwatar
+ java-design-patterns
+ 1.14.0-SNAPSHOT
+
+ event-asynchronous
+
+
+ junit
+ junit
+ test
+
+
+
diff --git a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/App.java b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/App.java
new file mode 100644
index 000000000..5a2565940
--- /dev/null
+++ b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/App.java
@@ -0,0 +1,206 @@
+/**
+ * The MIT License Copyright (c) 2014 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+package com.iluwatar.event.asynchronous;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+import java.util.Scanner;
+
+/**
+ *
+ * This application demonstrates the Event-based Asynchronous 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.
+ *
+ * The {@link EventManager} manages the events/threads that the user creates. Currently, the supported event operations
+ * are: start
, stop
, getStatus
. For Synchronous events, the user is unable to
+ * start another (Synchronous) event if one is already running at the time. The running event would have to either be
+ * stopped or completed before a new event can be started.
+ *
+ * The Event-based Asynchronous Pattern makes available the advantages of multithreaded applications while hiding many
+ * of the complex issues inherent in multithreaded design. Using a class that supports this pattern can allow you to:-
+ * (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 Event
+ *
+ */
+public class App {
+
+ public static final String PROP_FILE_NAME = "config.properties";
+
+ boolean interactiveMode = false;
+
+ /**
+ * Program entry point.
+ *
+ * @param args command line args
+ */
+ public static void main(String[] args) {
+ App app = new App();
+
+ app.setUp();
+ app.run();
+ }
+
+ /**
+ * App can run in interactive mode or not. Interactive mode == Allow user interaction with command line.
+ * Non-interactive is a quick sequential run through the available {@link EventManager} operations.
+ */
+ public void setUp() {
+ Properties prop = new Properties();
+
+ InputStream inputStream = App.class.getClassLoader().getResourceAsStream(PROP_FILE_NAME);
+
+ if (inputStream != null) {
+ try {
+ prop.load(inputStream);
+ } catch (IOException e) {
+ System.out.println(PROP_FILE_NAME + " was not found. Defaulting to non-interactive mode.");
+ }
+ String property = prop.getProperty("INTERACTIVE_MODE");
+ if (property.equalsIgnoreCase("YES")) {
+ interactiveMode = true;
+ }
+ }
+ }
+
+ /**
+ * Run program in either interactive mode or not.
+ */
+ public void run() {
+ if (interactiveMode) {
+ runInteractiveMode();
+ } else {
+ quickRun();
+ }
+ }
+
+ /**
+ * Run program in non-interactive mode.
+ */
+ public void quickRun() {
+ EventManager eventManager = new EventManager();
+
+ try {
+ // Create an Asynchronous event.
+ int aEventId = eventManager.createAsync(60);
+ System.out.println("Async Event [" + aEventId + "] has been created.");
+ eventManager.start(aEventId);
+ System.out.println("Async Event [" + aEventId + "] has been started.");
+
+ // Create a Synchronous event.
+ int sEventId = eventManager.create(60);
+ System.out.println("Sync Event [" + sEventId + "] has been created.");
+ eventManager.start(sEventId);
+ System.out.println("Sync Event [" + sEventId + "] has been started.");
+
+ eventManager.status(aEventId);
+ eventManager.status(sEventId);
+
+ eventManager.cancel(aEventId);
+ System.out.println("Async Event [" + aEventId + "] has been stopped.");
+ eventManager.cancel(sEventId);
+ System.out.println("Sync Event [" + sEventId + "] has been stopped.");
+
+ } catch (MaxNumOfEventsAllowedException | LongRunningEventException | EventDoesNotExistException
+ | InvalidOperationException e) {
+ System.out.println(e.getMessage());
+ }
+ }
+
+ /**
+ * Run program in interactive mode.
+ */
+ public void runInteractiveMode() {
+ EventManager eventManager = new EventManager();
+
+ Scanner s = new Scanner(System.in);
+ int option = -1;
+ while (option != 4) {
+ System.out.println("Hello. Would you like to boil some eggs?");
+ System.out.println("(1) BOIL AN EGG \n(2) STOP BOILING THIS EGG \n(3) HOW ARE MY EGGS? \n(4) EXIT");
+ System.out.print("Choose [1,2,3,4]: ");
+ option = s.nextInt();
+
+ if (option == 1) {
+ s.nextLine();
+ System.out.print("Boil multiple eggs at once (A) or boil them one-by-one (S)?: ");
+ String eventType = s.nextLine();
+ System.out.print("How long should this egg be boiled for (in seconds)?: ");
+ int eventTime = s.nextInt();
+ if (eventType.equalsIgnoreCase("A")) {
+ try {
+ int eventId = eventManager.createAsync(eventTime);
+ eventManager.start(eventId);
+ System.out.println("Egg [" + eventId + "] is being boiled.");
+ } catch (MaxNumOfEventsAllowedException | LongRunningEventException | EventDoesNotExistException e) {
+ System.out.println(e.getMessage());
+ }
+ } else if (eventType.equalsIgnoreCase("S")) {
+ try {
+ int eventId = eventManager.create(eventTime);
+ eventManager.start(eventId);
+ System.out.println("Egg [" + eventId + "] is being boiled.");
+ } catch (MaxNumOfEventsAllowedException | InvalidOperationException | LongRunningEventException
+ | EventDoesNotExistException e) {
+ System.out.println(e.getMessage());
+ }
+ } else {
+ System.out.println("Unknown event type.");
+ }
+ } else if (option == 2) {
+ System.out.print("Which egg?: ");
+ int eventId = s.nextInt();
+ try {
+ eventManager.cancel(eventId);
+ System.out.println("Egg [" + eventId + "] is removed from boiler.");
+ } catch (EventDoesNotExistException e) {
+ System.out.println(e.getMessage());
+ }
+ } else if (option == 3) {
+ s.nextLine();
+ System.out.print("Just one egg (O) OR all of them (A) ?: ");
+ String eggChoice = s.nextLine();
+
+ if (eggChoice.equalsIgnoreCase("O")) {
+ System.out.print("Which egg?: ");
+ int eventId = s.nextInt();
+ try {
+ eventManager.status(eventId);
+ } catch (EventDoesNotExistException e) {
+ System.out.println(e.getMessage());
+ }
+ } else if (eggChoice.equalsIgnoreCase("A")) {
+ eventManager.statusOfAllEvents();
+ }
+ } else if (option == 4) {
+ eventManager.shutdown();
+ }
+ }
+
+ s.close();
+ }
+
+}
diff --git a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/Event.java b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/Event.java
new file mode 100644
index 000000000..5e557fff2
--- /dev/null
+++ b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/Event.java
@@ -0,0 +1,101 @@
+/**
+ * The MIT License Copyright (c) 2014 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+package com.iluwatar.event.asynchronous;
+
+/**
+ *
+ * Each Event runs as a separate/individual thread.
+ *
+ */
+public class Event implements IEvent, Runnable {
+
+ private int eventId;
+ private int eventTime;
+ private boolean isSynchronous;
+ private Thread thread;
+ private boolean isComplete = false;
+ private ThreadCompleteListener eventListener;
+
+ /**
+ *
+ * @param eventId event ID
+ * @param eventTime event time
+ * @param isSynchronous is of synchronous type
+ */
+ public Event(final int eventId, final int eventTime, final boolean isSynchronous) {
+ this.eventId = eventId;
+ this.eventTime = eventTime;
+ this.isSynchronous = isSynchronous;
+ }
+
+ public boolean isSynchronous() {
+ return isSynchronous;
+ }
+
+ @Override
+ public void start() {
+ thread = new Thread(this);
+ thread.start();
+ }
+
+ @Override
+ public void stop() {
+ if (null == thread) {
+ return;
+ }
+ thread.interrupt();
+ }
+
+ @Override
+ public void status() {
+ if (!isComplete) {
+ System.out.println("[" + eventId + "] is not done.");
+ } else {
+ System.out.println("[" + eventId + "] is done.");
+ }
+ }
+
+ @Override
+ public void run() {
+ long currentTime = System.currentTimeMillis();
+ long endTime = currentTime + (eventTime * 1000);
+ while (System.currentTimeMillis() < endTime) {
+ try {
+ Thread.sleep(1000); // Sleep for 1 second.
+ } catch (InterruptedException e) {
+ return;
+ }
+ }
+ isComplete = true;
+ completed();
+ }
+
+ public final void addListener(final ThreadCompleteListener listener) {
+ this.eventListener = listener;
+ }
+
+ public final void removeListener(final ThreadCompleteListener listener) {
+ this.eventListener = null;
+ }
+
+ private final void completed() {
+ if (eventListener != null) {
+ eventListener.completedEventHandler(eventId);
+ }
+ }
+
+}
diff --git a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/EventDoesNotExistException.java b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/EventDoesNotExistException.java
new file mode 100644
index 000000000..77c1d479b
--- /dev/null
+++ b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/EventDoesNotExistException.java
@@ -0,0 +1,26 @@
+/**
+ * The MIT License Copyright (c) 2014 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+package com.iluwatar.event.asynchronous;
+
+public class EventDoesNotExistException extends Exception {
+
+ private static final long serialVersionUID = -3398463738273811509L;
+
+ public EventDoesNotExistException(String message) {
+ super(message);
+ }
+}
diff --git a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/EventManager.java b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/EventManager.java
new file mode 100644
index 000000000..dae995e38
--- /dev/null
+++ b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/EventManager.java
@@ -0,0 +1,218 @@
+/**
+ * The MIT License Copyright (c) 2014 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+package com.iluwatar.event.asynchronous;
+
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Random;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ *
+ * EventManager handles and maintains a pool of event threads. {@link Event} threads are created upon user request. Thre
+ * are two types of events; Asynchronous and Synchronous. There can be multiple Asynchronous events running at once but
+ * only one Synchronous event running at a time. Currently supported event operations are: start, stop, and getStatus.
+ * Once an event is complete, it then notifies EventManager through a listener. The EventManager then takes the event
+ * out of the pool.
+ *
+ */
+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 MIN_ID = 1;
+ public static final int MAX_ID = MAX_RUNNING_EVENTS;
+ public static final int MAX_EVENT_TIME = 1800; // in seconds / 30 minutes.
+ private int currentlyRunningSyncEvent = -1;
+ private Random rand;
+ private Map eventPool;
+
+ /**
+ * EventManager constructor.
+ *
+ */
+ public EventManager() {
+ rand = new Random(1);
+ eventPool = new ConcurrentHashMap(MAX_RUNNING_EVENTS);
+
+ }
+
+ /**
+ * Create a Synchronous event.
+ *
+ * @param eventTime Time an event should run for.
+ * @return eventId
+ * @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 LongRunningEventException Long running events are not allowed in the app.
+ */
+ public int create(int eventTime)
+ throws MaxNumOfEventsAllowedException, InvalidOperationException, LongRunningEventException {
+ if (currentlyRunningSyncEvent != -1) {
+ throw new InvalidOperationException(
+ "Event [" + currentlyRunningSyncEvent + "] is still running. Please wait until it finishes and try again.");
+ }
+
+ int eventId = createEvent(eventTime, true);
+ currentlyRunningSyncEvent = eventId;
+
+ return eventId;
+ }
+
+ /**
+ * Create an Asynchronous event.
+ *
+ * @param eventTime Time an event should run for.
+ * @return eventId
+ * @throws MaxNumOfEventsAllowedException When too many events are running at a time.
+ * @throws LongRunningEventException Long running events are not allowed in the app.
+ */
+ public int createAsync(int eventTime) throws MaxNumOfEventsAllowedException, LongRunningEventException {
+ return createEvent(eventTime, false);
+ }
+
+ private int createEvent(int eventTime, boolean isSynchronous)
+ throws MaxNumOfEventsAllowedException, LongRunningEventException {
+ if (eventPool.size() == MAX_RUNNING_EVENTS) {
+ throw new MaxNumOfEventsAllowedException("Too many events are running at the moment. Please try again later.");
+ }
+
+ if (eventTime >= MAX_EVENT_TIME) {
+ throw new LongRunningEventException(
+ "Maximum event time allowed is " + MAX_EVENT_TIME + " seconds. Please try again.");
+ }
+
+ int newEventId = generateId();
+
+ Event newEvent = new Event(newEventId, eventTime, isSynchronous);
+ newEvent.addListener(this);
+ eventPool.put(newEventId, newEvent);
+
+ return newEventId;
+ }
+
+ /**
+ * Starts event.
+ *
+ * @param eventId The event that needs to be started.
+ * @throws EventDoesNotExistException If event does not exist in our eventPool.
+ */
+ public void start(int eventId) throws EventDoesNotExistException {
+ if (!eventPool.containsKey(eventId)) {
+ throw new EventDoesNotExistException(eventId + " does not exist.");
+ }
+
+ eventPool.get(eventId).start();
+ }
+
+ /**
+ * Stops event.
+ *
+ * @param eventId The event that needs to be stopped.
+ * @throws EventDoesNotExistException If event does not exist in our eventPool.
+ */
+ public void cancel(int eventId) throws EventDoesNotExistException {
+ if (!eventPool.containsKey(eventId)) {
+ throw new EventDoesNotExistException(eventId + " does not exist.");
+ }
+
+ if (eventId == currentlyRunningSyncEvent) {
+ currentlyRunningSyncEvent = -1;
+ }
+
+ eventPool.get(eventId).stop();
+ eventPool.remove(eventId);
+ }
+
+ /**
+ * Get status of a running event.
+ *
+ * @param eventId The event to inquire status of.
+ * @throws EventDoesNotExistException If event does not exist in our eventPool.
+ */
+ public void status(int eventId) throws EventDoesNotExistException {
+ if (!eventPool.containsKey(eventId)) {
+ throw new EventDoesNotExistException(eventId + " does not exist.");
+ }
+
+ eventPool.get(eventId).status();
+ }
+
+ /**
+ * Gets status of all running events.
+ */
+ @SuppressWarnings("rawtypes")
+ public void statusOfAllEvents() {
+ Iterator it = eventPool.entrySet().iterator();
+ while (it.hasNext()) {
+ Map.Entry pair = (Map.Entry) it.next();
+ ((Event) pair.getValue()).status();
+ }
+ }
+
+ /**
+ * Stop all running events.
+ */
+ @SuppressWarnings("rawtypes")
+ public void shutdown() {
+ Iterator it = eventPool.entrySet().iterator();
+ while (it.hasNext()) {
+ Map.Entry pair = (Map.Entry) it.next();
+ ((Event) pair.getValue()).stop();
+ }
+ }
+
+ /**
+ * Returns a pseudo-random number between min and max, inclusive. The difference between min and max can be at most
+ * Integer.MAX_VALUE - 1
.
+ */
+ private int generateId() {
+ // nextInt is normally exclusive of the top value,
+ // so add 1 to make it inclusive
+ int randomNum = rand.nextInt((MAX_ID - MIN_ID) + 1) + MIN_ID;
+ while (eventPool.containsKey(randomNum)) {
+ randomNum = rand.nextInt((MAX_ID - MIN_ID) + 1) + MIN_ID;
+ }
+
+ return randomNum;
+ }
+
+ /**
+ * Callback from an {@link Event} (once it is complete). The Event is then removed from the pool.
+ */
+ @Override
+ public void completedEventHandler(int eventId) {
+ eventPool.get(eventId).status();
+ if (eventPool.get(eventId).isSynchronous()) {
+ currentlyRunningSyncEvent = -1;
+ }
+ eventPool.remove(eventId);
+ }
+
+ /**
+ * Getter method for event pool.
+ */
+ public Map getEventPool() {
+ return eventPool;
+ }
+
+ /**
+ * Get number of currently running Synchronous events.
+ */
+ public int numOfCurrentlyRunningSyncEvent() {
+ return currentlyRunningSyncEvent;
+ }
+}
diff --git a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/IEvent.java b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/IEvent.java
new file mode 100644
index 000000000..bcd78b6c0
--- /dev/null
+++ b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/IEvent.java
@@ -0,0 +1,27 @@
+/**
+ * The MIT License Copyright (c) 2014 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+package com.iluwatar.event.asynchronous;
+
+public interface IEvent {
+
+ void start();
+
+ void stop();
+
+ void status();
+
+}
diff --git a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/InvalidOperationException.java b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/InvalidOperationException.java
new file mode 100644
index 000000000..4fd5b0eed
--- /dev/null
+++ b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/InvalidOperationException.java
@@ -0,0 +1,27 @@
+/**
+ * The MIT License Copyright (c) 2014 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+package com.iluwatar.event.asynchronous;
+
+public class InvalidOperationException extends Exception {
+
+ private static final long serialVersionUID = -6191545255213410803L;
+
+ public InvalidOperationException(String message) {
+ super(message);
+ }
+
+}
diff --git a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/LongRunningEventException.java b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/LongRunningEventException.java
new file mode 100644
index 000000000..6817b1dd8
--- /dev/null
+++ b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/LongRunningEventException.java
@@ -0,0 +1,26 @@
+/**
+ * The MIT License Copyright (c) 2014 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+package com.iluwatar.event.asynchronous;
+
+public class LongRunningEventException extends Exception {
+
+ private static final long serialVersionUID = -483423544320148809L;
+
+ public LongRunningEventException(String message) {
+ super(message);
+ }
+}
diff --git a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/MaxNumOfEventsAllowedException.java b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/MaxNumOfEventsAllowedException.java
new file mode 100644
index 000000000..9f8f2891c
--- /dev/null
+++ b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/MaxNumOfEventsAllowedException.java
@@ -0,0 +1,26 @@
+/**
+ * The MIT License Copyright (c) 2014 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+package com.iluwatar.event.asynchronous;
+
+public class MaxNumOfEventsAllowedException extends Exception {
+
+ private static final long serialVersionUID = -8430876973516292695L;
+
+ public MaxNumOfEventsAllowedException(String message) {
+ super(message);
+ }
+}
diff --git a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/ThreadCompleteListener.java b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/ThreadCompleteListener.java
new file mode 100644
index 000000000..fd62a3e80
--- /dev/null
+++ b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/ThreadCompleteListener.java
@@ -0,0 +1,21 @@
+/**
+ * The MIT License Copyright (c) 2014 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+package com.iluwatar.event.asynchronous;
+
+public interface ThreadCompleteListener {
+ void completedEventHandler(final int eventId);
+}
diff --git a/event-asynchronous/src/main/resources/config.properties b/event-asynchronous/src/main/resources/config.properties
new file mode 100644
index 000000000..edbe90e05
--- /dev/null
+++ b/event-asynchronous/src/main/resources/config.properties
@@ -0,0 +1 @@
+INTERACTIVE_MODE=NO
\ No newline at end of file
diff --git a/event-asynchronous/src/test/java/com/iluwatar/event/asynchronous/AppTest.java b/event-asynchronous/src/test/java/com/iluwatar/event/asynchronous/AppTest.java
new file mode 100644
index 000000000..8736fcf77
--- /dev/null
+++ b/event-asynchronous/src/test/java/com/iluwatar/event/asynchronous/AppTest.java
@@ -0,0 +1,32 @@
+/**
+ * The MIT License Copyright (c) 2014 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+package com.iluwatar.event.asynchronous;
+
+import java.io.IOException;
+
+import org.junit.Test;
+
+/**
+ * Tests that EventAsynchronous example runs without errors.
+ */
+public class AppTest {
+ @Test
+ public void test() throws IOException {
+ String[] args = {};
+ App.main(args);
+ }
+}
diff --git a/event-asynchronous/src/test/java/com/iluwatar/event/asynchronous/EventAsynchronousTest.java b/event-asynchronous/src/test/java/com/iluwatar/event/asynchronous/EventAsynchronousTest.java
new file mode 100644
index 000000000..213439203
--- /dev/null
+++ b/event-asynchronous/src/test/java/com/iluwatar/event/asynchronous/EventAsynchronousTest.java
@@ -0,0 +1,135 @@
+/**
+ * The MIT License Copyright (c) 2014 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+package com.iluwatar.event.asynchronous;
+
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ *
+ * Application test
+ *
+ */
+public class EventAsynchronousTest {
+ App app;
+
+ @Before
+ public void setUp() {
+ app = new App();
+ }
+
+ @Test
+ public void testAsynchronousEvent() {
+ EventManager eventManager = new EventManager();
+ try {
+ int aEventId = eventManager.createAsync(60);
+ eventManager.start(aEventId);
+ assertTrue(eventManager.getEventPool().size() == 1);
+ assertTrue(eventManager.getEventPool().size() < EventManager.MAX_RUNNING_EVENTS);
+ assertTrue(eventManager.numOfCurrentlyRunningSyncEvent() == -1);
+ eventManager.cancel(aEventId);
+ assertTrue(eventManager.getEventPool().size() == 0);
+ } catch (MaxNumOfEventsAllowedException | LongRunningEventException | EventDoesNotExistException e) {
+ System.out.println(e.getMessage());
+ }
+ }
+
+ @Test
+ public void testSynchronousEvent() {
+ EventManager eventManager = new EventManager();
+ try {
+ int sEventId = eventManager.create(60);
+ eventManager.start(sEventId);
+ assertTrue(eventManager.getEventPool().size() == 1);
+ assertTrue(eventManager.getEventPool().size() < EventManager.MAX_RUNNING_EVENTS);
+ assertTrue(eventManager.numOfCurrentlyRunningSyncEvent() != -1);
+ eventManager.cancel(sEventId);
+ assertTrue(eventManager.getEventPool().size() == 0);
+ } catch (MaxNumOfEventsAllowedException | LongRunningEventException | EventDoesNotExistException
+ | InvalidOperationException e) {
+ System.out.println(e.getMessage());
+ }
+ }
+
+ @Test(expected = InvalidOperationException.class)
+ public void testUnsuccessfulSynchronousEvent() throws InvalidOperationException {
+ EventManager eventManager = new EventManager();
+ try {
+ int sEventId = eventManager.create(60);
+ eventManager.start(sEventId);
+ sEventId = eventManager.create(60);
+ eventManager.start(sEventId);
+ } catch (MaxNumOfEventsAllowedException | LongRunningEventException | EventDoesNotExistException e) {
+ System.out.println(e.getMessage());
+ }
+ }
+
+ @Test
+ public void testFullSynchronousEvent() {
+ EventManager eventManager = new EventManager();
+ try {
+ int eventTime = 1;
+
+ int sEventId = eventManager.create(eventTime);
+ assertTrue(eventManager.getEventPool().size() == 1);
+ eventManager.start(sEventId);
+
+ long currentTime = System.currentTimeMillis();
+ long endTime = currentTime + (eventTime + 2 * 1000); // +2 to give a bit of buffer time for event to
+ // complete
+ // properly.
+ while (System.currentTimeMillis() < endTime) {
+ }
+
+ assertTrue(eventManager.getEventPool().size() == 0);
+
+ } catch (MaxNumOfEventsAllowedException | LongRunningEventException | EventDoesNotExistException
+ | InvalidOperationException e) {
+ System.out.println(e.getMessage());
+ }
+ }
+
+ @Test
+ public void testFullAsynchronousEvent() {
+ EventManager eventManager = new EventManager();
+ try {
+ int eventTime = 1;
+
+ int aEventId1 = eventManager.createAsync(eventTime);
+ int aEventId2 = eventManager.createAsync(eventTime);
+ int aEventId3 = eventManager.createAsync(eventTime);
+ assertTrue(eventManager.getEventPool().size() == 3);
+
+ eventManager.start(aEventId1);
+ eventManager.start(aEventId2);
+ eventManager.start(aEventId3);
+
+ long currentTime = System.currentTimeMillis();
+ long endTime = currentTime + (eventTime + 2 * 1000); // +2 to give a bit of buffer time for event to complete
+ // properly.
+ while (System.currentTimeMillis() < endTime) {
+ }
+
+ assertTrue(eventManager.getEventPool().size() == 0);
+
+ } catch (MaxNumOfEventsAllowedException | LongRunningEventException | EventDoesNotExistException e) {
+ System.out.println(e.getMessage());
+ }
+ }
+}
diff --git a/pom.xml b/pom.xml
index 144b8efff..538058a81 100644
--- a/pom.xml
+++ b/pom.xml
@@ -132,7 +132,8 @@
aggregator-microservices
promise
page-object
-
+ event-asynchronous
+