Skip to content

Commit

Permalink
Issue #469: Implementation of Event-based Asynchronous pattern
Browse files Browse the repository at this point in the history
  • Loading branch information
WSSIA committed Sep 3, 2016
1 parent ff23e90 commit 2d99061
Show file tree
Hide file tree
Showing 16 changed files with 860 additions and 0 deletions.
28 changes: 28 additions & 0 deletions event-asynchronous/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
layout: pattern
title: Event-based Asynchronous
folder: event-asynchronous
permalink: /patterns/event-asynchronous/
categories: Other
tags:
- 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.

![alt text](./etc/event-asynchronous.png "Event-based Asynchronous")

## 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)
Binary file added event-asynchronous/etc/event-asynchronous.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
110 changes: 110 additions & 0 deletions event-asynchronous/etc/event-asynchronous.ucls
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
<?xml version="1.0" encoding="UTF-8"?>
<class-diagram version="1.1.10" icons="true" automaticImage="PNG" always-add-relationships="false"
generalizations="true" realizations="true" associations="true" dependencies="false" nesting-relationships="true"
router="FAN">
<class id="1" language="java" name="com.iluwatar.event.asynchronous.App" project="event-asynchronous"
file="/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/App.java" binary="false"
corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="629" y="221"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="false" package="false" protected="false" private="false" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</class>
<class id="2" language="java" name="com.iluwatar.event.asynchronous.Event" project="event-asynchronous"
file="/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/Event.java" binary="false"
corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="195" y="475"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="false" package="false" protected="false" private="false" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</class>
<class id="3" language="java" name="com.iluwatar.event.asynchronous.EventManager" project="event-asynchronous"
file="/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/EventManager.java" binary="false"
corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="575" y="475"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="false" package="false" protected="false" private="false" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</class>
<interface id="4" language="java" name="com.iluwatar.event.asynchronous.IEvent" project="event-asynchronous"
file="/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/IEvent.java" binary="false"
corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="196" y="197"/>
<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>
</interface>
<interface id="5" language="java" name="com.iluwatar.event.asynchronous.ThreadCompleteListener"
project="event-asynchronous"
file="/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/ThreadCompleteListener.java" binary="false"
corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="396" y="229"/>
<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>
</interface>
<class id="6" language="java" name="com.iluwatar.event.asynchronous.EventAsynchronousTest"
project="event-asynchronous"
file="/event-asynchronous/src/test/java/com/iluwatar/event/asynchronous/EventAsynchronousTest.java" binary="false"
corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="924" y="220"/>
<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>
<association id="7">
<bendpoint x="433" y="475"/>
<end type="SOURCE" refId="3" navigable="false">
<attribute id="8" name="eventPool"/>
<multiplicity id="9" minimum="0" maximum="2147483647"/>
</end>
<end type="TARGET" refId="2" navigable="true"/>
<display labels="true" multiplicity="true"/>
</association>
<association id="10">
<end type="SOURCE" refId="2" navigable="false">
<attribute id="11" name="eventListener">
<position height="18" width="74" x="250" y="287"/>
</attribute>
<multiplicity id="12" minimum="0" maximum="1"/>
</end>
<end type="TARGET" refId="5" navigable="true"/>
<display labels="true" multiplicity="true"/>
</association>
<association id="13">
<end type="SOURCE" refId="6" navigable="false">
<attribute id="14" name="app"/>
<multiplicity id="15" minimum="0" maximum="1">
<position height="16" width="23" x="714" y="226"/>
</multiplicity>
</end>
<end type="TARGET" refId="1" navigable="true"/>
<display labels="true" multiplicity="true"/>
</association>
<realization id="16">
<end type="SOURCE" refId="2"/>
<end type="TARGET" refId="4"/>
</realization>
<realization id="17">
<end type="SOURCE" refId="3"/>
<end type="TARGET" refId="5"/>
</realization>
<classifier-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"/>
</classifier-display>
<association-display labels="true" multiplicity="true"/>
</class-diagram>
42 changes: 42 additions & 0 deletions event-asynchronous/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?xml version="1.0"?>
<!--
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.
-->
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.iluwatar</groupId>
<artifactId>java-design-patterns</artifactId>
<version>1.13.0-SNAPSHOT</version>
</parent>
<artifactId>event-asynchronous</artifactId>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
/**
* 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 <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.
*
* The {@link EventManager} manages the events/threads that the user creates. Currently, the supported event operations
* are: <code>start</code>, <code>stop</code>, <code>getStatus</code>. 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 {

boolean interactiveMode = false;

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();
String propFileName = "config.properties";

InputStream inputStream = App.class.getClassLoader().getResourceAsStream(propFileName);

if (inputStream != null) {
try {
prop.load(inputStream);
} catch (IOException e) {
}
String property = prop.getProperty("INTERACTIVE_MODE");
if (property.equalsIgnoreCase("YES")) {
interactiveMode = true;
}
}
}

public void run() {
if (interactiveMode) {
runInteractiveMode();
} else {
quickRun();
}
}

public void quickRun() {
EventManager eventManager = new EventManager();

try {
// Create an Asynchronous event.
int aEventID = eventManager.createAsyncEvent(60);
System.out.println("Event [" + aEventID + "] has been created.");
eventManager.startEvent(aEventID);
System.out.println("Event [" + aEventID + "] has been started.");

// Create a Synchronous event.
int sEventID = eventManager.createSyncEvent(60);
System.out.println("Event [" + sEventID + "] has been created.");
eventManager.startEvent(sEventID);
System.out.println("Event [" + sEventID + "] has been started.");

eventManager.getStatus(aEventID);
eventManager.getStatus(sEventID);

eventManager.stopEvent(aEventID);
System.out.println("Event [" + aEventID + "] has been stopped.");
eventManager.stopEvent(sEventID);
System.out.println("Event [" + sEventID + "] has been stopped.");

} catch (MaxNumOfEventsAllowedException | LongRunningEventException | EventDoesNotExistException
| InvalidOperationException e) {
System.out.println(e.getMessage());
}
}

public void runInteractiveMode() {
EventManager eventManager = new EventManager();

Scanner s = new Scanner(System.in);
int option = 0;
option = -1;
while (option != 5) {
System.out
.println("(1) START_EVENT \n(2) STOP_EVENT \n(3) STATUS_OF_EVENT \n(4) STATUS_OF_ALL_EVENTS \n(5) EXIT");
System.out.print("Choose [1,2,3,4,5]: ");
option = s.nextInt();

if (option == 1) {
s.nextLine();
System.out.print("(A)sync or (S)ync event?: ");
String eventType = s.nextLine();
System.out.print("How long should this event run for (in seconds)?: ");
int eventTime = s.nextInt();
if (eventType.equalsIgnoreCase("A")) {
try {
int eventID = eventManager.createAsyncEvent(eventTime);
System.out.println("Event [" + eventID + "] has been created.");
eventManager.startEvent(eventID);
System.out.println("Event [" + eventID + "] has been started.");
} catch (MaxNumOfEventsAllowedException | LongRunningEventException | EventDoesNotExistException e) {
System.out.println(e.getMessage());
}
} else if (eventType.equalsIgnoreCase("S")) {
try {
int eventID = eventManager.createSyncEvent(eventTime);
System.out.println("Event [" + eventID + "] has been created.");
eventManager.startEvent(eventID);
System.out.println("Event [" + eventID + "] has been started.");
} 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("Event ID: ");
int eventID = s.nextInt();
try {
eventManager.stopEvent(eventID);
System.out.println("Event [" + eventID + "] has been stopped.");
} catch (EventDoesNotExistException e) {
System.out.println(e.getMessage());
}
} else if (option == 3) {
System.out.print("Event ID: ");
int eventID = s.nextInt();
try {
eventManager.getStatus(eventID);
} catch (EventDoesNotExistException e) {
System.out.println(e.getMessage());
}
} else if (option == 4) {
eventManager.getStatusOfAllEvents();
}
}

s.close();
}

}

0 comments on commit 2d99061

Please sign in to comment.