-
-
Notifications
You must be signed in to change notification settings - Fork 26.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Issue #469: Implementation of Event-based Asynchronous pattern
- Loading branch information
WSSIA
committed
Sep 3, 2016
1 parent
ff23e90
commit 2d99061
Showing
16 changed files
with
860 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> |
185 changes: 185 additions & 0 deletions
185
event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/App.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | ||
} | ||
|
||
} |
Oops, something went wrong.