Skip to content

Commit 2d99061

Browse files
author
WSSIA
committed
Issue iluwatar#469: Implementation of Event-based Asynchronous pattern
1 parent ff23e90 commit 2d99061

File tree

16 files changed

+860
-0
lines changed

16 files changed

+860
-0
lines changed

event-asynchronous/README.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
---
2+
layout: pattern
3+
title: Event-based Asynchronous
4+
folder: event-asynchronous
5+
permalink: /patterns/event-asynchronous/
6+
categories: Other
7+
tags:
8+
- Java
9+
---
10+
11+
## Intent
12+
The Event-based Asynchronous Pattern makes available the advantages of multithreaded applications while hiding many
13+
of the complex issues inherent in multithreaded design. Using a class that supports this pattern can allow you to:-
14+
(1) Perform time-consuming tasks, such as downloads and database operations, "in the background," without interrupting your application.
15+
(2) Execute multiple operations simultaneously, receiving notifications when each completes.
16+
(3) Wait for resources to become available without stopping ("hanging") your application.
17+
(4) Communicate with pending asynchronous operations using the familiar events-and-delegates model.
18+
19+
![alt text](./etc/event-asynchronous.png "Event-based Asynchronous")
20+
21+
## Applicability
22+
Use the Event-based Asynchronous pattern(s) when
23+
24+
* Time-consuming tasks are needed to run in the background without disrupting the current application.
25+
26+
## Credits
27+
28+
* [Event-based Asynchronous Pattern Overview](https://msdn.microsoft.com/en-us/library/wewwczdw%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396)
30.7 KB
Loading
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<class-diagram version="1.1.10" icons="true" automaticImage="PNG" always-add-relationships="false"
3+
generalizations="true" realizations="true" associations="true" dependencies="false" nesting-relationships="true"
4+
router="FAN">
5+
<class id="1" language="java" name="com.iluwatar.event.asynchronous.App" project="event-asynchronous"
6+
file="/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/App.java" binary="false"
7+
corner="BOTTOM_RIGHT">
8+
<position height="-1" width="-1" x="629" y="221"/>
9+
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
10+
sort-features="false" accessors="true" visibility="true">
11+
<attributes public="false" package="false" protected="false" private="false" static="true"/>
12+
<operations public="true" package="true" protected="true" private="true" static="true"/>
13+
</display>
14+
</class>
15+
<class id="2" language="java" name="com.iluwatar.event.asynchronous.Event" project="event-asynchronous"
16+
file="/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/Event.java" binary="false"
17+
corner="BOTTOM_RIGHT">
18+
<position height="-1" width="-1" x="195" y="475"/>
19+
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
20+
sort-features="false" accessors="true" visibility="true">
21+
<attributes public="false" package="false" protected="false" private="false" static="true"/>
22+
<operations public="true" package="true" protected="true" private="true" static="true"/>
23+
</display>
24+
</class>
25+
<class id="3" language="java" name="com.iluwatar.event.asynchronous.EventManager" project="event-asynchronous"
26+
file="/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/EventManager.java" binary="false"
27+
corner="BOTTOM_RIGHT">
28+
<position height="-1" width="-1" x="575" y="475"/>
29+
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
30+
sort-features="false" accessors="true" visibility="true">
31+
<attributes public="false" package="false" protected="false" private="false" static="true"/>
32+
<operations public="true" package="true" protected="true" private="true" static="true"/>
33+
</display>
34+
</class>
35+
<interface id="4" language="java" name="com.iluwatar.event.asynchronous.IEvent" project="event-asynchronous"
36+
file="/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/IEvent.java" binary="false"
37+
corner="BOTTOM_RIGHT">
38+
<position height="-1" width="-1" x="196" y="197"/>
39+
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
40+
sort-features="false" accessors="true" visibility="true">
41+
<attributes public="true" package="true" protected="true" private="true" static="true"/>
42+
<operations public="true" package="true" protected="true" private="true" static="true"/>
43+
</display>
44+
</interface>
45+
<interface id="5" language="java" name="com.iluwatar.event.asynchronous.ThreadCompleteListener"
46+
project="event-asynchronous"
47+
file="/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/ThreadCompleteListener.java" binary="false"
48+
corner="BOTTOM_RIGHT">
49+
<position height="-1" width="-1" x="396" y="229"/>
50+
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
51+
sort-features="false" accessors="true" visibility="true">
52+
<attributes public="true" package="true" protected="true" private="true" static="true"/>
53+
<operations public="true" package="true" protected="true" private="true" static="true"/>
54+
</display>
55+
</interface>
56+
<class id="6" language="java" name="com.iluwatar.event.asynchronous.EventAsynchronousTest"
57+
project="event-asynchronous"
58+
file="/event-asynchronous/src/test/java/com/iluwatar/event/asynchronous/EventAsynchronousTest.java" binary="false"
59+
corner="BOTTOM_RIGHT">
60+
<position height="-1" width="-1" x="924" y="220"/>
61+
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
62+
sort-features="false" accessors="true" visibility="true">
63+
<attributes public="true" package="true" protected="true" private="true" static="true"/>
64+
<operations public="true" package="true" protected="true" private="true" static="true"/>
65+
</display>
66+
</class>
67+
<association id="7">
68+
<bendpoint x="433" y="475"/>
69+
<end type="SOURCE" refId="3" navigable="false">
70+
<attribute id="8" name="eventPool"/>
71+
<multiplicity id="9" minimum="0" maximum="2147483647"/>
72+
</end>
73+
<end type="TARGET" refId="2" navigable="true"/>
74+
<display labels="true" multiplicity="true"/>
75+
</association>
76+
<association id="10">
77+
<end type="SOURCE" refId="2" navigable="false">
78+
<attribute id="11" name="eventListener">
79+
<position height="18" width="74" x="250" y="287"/>
80+
</attribute>
81+
<multiplicity id="12" minimum="0" maximum="1"/>
82+
</end>
83+
<end type="TARGET" refId="5" navigable="true"/>
84+
<display labels="true" multiplicity="true"/>
85+
</association>
86+
<association id="13">
87+
<end type="SOURCE" refId="6" navigable="false">
88+
<attribute id="14" name="app"/>
89+
<multiplicity id="15" minimum="0" maximum="1">
90+
<position height="16" width="23" x="714" y="226"/>
91+
</multiplicity>
92+
</end>
93+
<end type="TARGET" refId="1" navigable="true"/>
94+
<display labels="true" multiplicity="true"/>
95+
</association>
96+
<realization id="16">
97+
<end type="SOURCE" refId="2"/>
98+
<end type="TARGET" refId="4"/>
99+
</realization>
100+
<realization id="17">
101+
<end type="SOURCE" refId="3"/>
102+
<end type="TARGET" refId="5"/>
103+
</realization>
104+
<classifier-display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
105+
sort-features="false" accessors="true" visibility="true">
106+
<attributes public="true" package="true" protected="true" private="true" static="true"/>
107+
<operations public="true" package="true" protected="true" private="true" static="true"/>
108+
</classifier-display>
109+
<association-display labels="true" multiplicity="true"/>
110+
</class-diagram>

event-asynchronous/pom.xml

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?xml version="1.0"?>
2+
<!--
3+
4+
The MIT License
5+
Copyright (c) 2014 Ilkka Seppälä
6+
7+
Permission is hereby granted, free of charge, to any person obtaining a copy
8+
of this software and associated documentation files (the "Software"), to deal
9+
in the Software without restriction, including without limitation the rights
10+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
copies of the Software, and to permit persons to whom the Software is
12+
furnished to do so, subject to the following conditions:
13+
14+
The above copyright notice and this permission notice shall be included in
15+
all copies or substantial portions of the Software.
16+
17+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23+
THE SOFTWARE.
24+
25+
-->
26+
<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"
27+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
28+
<modelVersion>4.0.0</modelVersion>
29+
<parent>
30+
<groupId>com.iluwatar</groupId>
31+
<artifactId>java-design-patterns</artifactId>
32+
<version>1.13.0-SNAPSHOT</version>
33+
</parent>
34+
<artifactId>event-asynchronous</artifactId>
35+
<dependencies>
36+
<dependency>
37+
<groupId>junit</groupId>
38+
<artifactId>junit</artifactId>
39+
<scope>test</scope>
40+
</dependency>
41+
</dependencies>
42+
</project>
Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
/**
2+
* The MIT License Copyright (c) 2014 Ilkka Seppälä
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
5+
* documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
6+
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
7+
* permit persons to whom the Software is furnished to do so, subject to the following conditions:
8+
*
9+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
10+
* Software.
11+
*
12+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
13+
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
14+
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
15+
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
16+
*/
17+
package com.iluwatar.event.asynchronous;
18+
19+
import java.io.IOException;
20+
import java.io.InputStream;
21+
import java.util.Properties;
22+
import java.util.Scanner;
23+
24+
/**
25+
*
26+
* This application demonstrates the <b>Event-based Asynchronous</b> pattern. Essentially, users (of the pattern) may
27+
* choose to run events in an Asynchronous or Synchronous mode. There can be multiple Asynchronous events running at
28+
* once but only one Synchronous event can run at a time. Asynchronous events are synonymous to multi-threads. The key
29+
* point here is that the threads run in the background and the user is free to carry on with other processes. Once an
30+
* event is complete, the appropriate listener/callback method will be called. The listener then proceeds to carry out
31+
* further processing depending on the needs of the user.
32+
*
33+
* The {@link EventManager} manages the events/threads that the user creates. Currently, the supported event operations
34+
* are: <code>start</code>, <code>stop</code>, <code>getStatus</code>. For Synchronous events, the user is unable to
35+
* start another (Synchronous) event if one is already running at the time. The running event would have to either be
36+
* stopped or completed before a new event can be started.
37+
*
38+
* The Event-based Asynchronous Pattern makes available the advantages of multithreaded applications while hiding many
39+
* of the complex issues inherent in multithreaded design. Using a class that supports this pattern can allow you to:-
40+
* (1) Perform time-consuming tasks, such as downloads and database operations, "in the background," without
41+
* interrupting your application. (2) Execute multiple operations simultaneously, receiving notifications when each
42+
* completes. (3) Wait for resources to become available without stopping ("hanging") your application. (4) Communicate
43+
* with pending asynchronous operations using the familiar events-and-delegates model.
44+
*
45+
* @see EventManager
46+
* @see Event
47+
*
48+
*/
49+
public class App {
50+
51+
boolean interactiveMode = false;
52+
53+
public static void main(String[] args) {
54+
App app = new App();
55+
56+
app.setUp();
57+
app.run();
58+
}
59+
60+
/**
61+
* App can run in interactive mode or not. Interactive mode == Allow user interaction with command line.
62+
* Non-interactive is a quick sequential run through the available {@link EventManager} operations.
63+
*/
64+
public void setUp() {
65+
Properties prop = new Properties();
66+
String propFileName = "config.properties";
67+
68+
InputStream inputStream = App.class.getClassLoader().getResourceAsStream(propFileName);
69+
70+
if (inputStream != null) {
71+
try {
72+
prop.load(inputStream);
73+
} catch (IOException e) {
74+
}
75+
String property = prop.getProperty("INTERACTIVE_MODE");
76+
if (property.equalsIgnoreCase("YES")) {
77+
interactiveMode = true;
78+
}
79+
}
80+
}
81+
82+
public void run() {
83+
if (interactiveMode) {
84+
runInteractiveMode();
85+
} else {
86+
quickRun();
87+
}
88+
}
89+
90+
public void quickRun() {
91+
EventManager eventManager = new EventManager();
92+
93+
try {
94+
// Create an Asynchronous event.
95+
int aEventID = eventManager.createAsyncEvent(60);
96+
System.out.println("Event [" + aEventID + "] has been created.");
97+
eventManager.startEvent(aEventID);
98+
System.out.println("Event [" + aEventID + "] has been started.");
99+
100+
// Create a Synchronous event.
101+
int sEventID = eventManager.createSyncEvent(60);
102+
System.out.println("Event [" + sEventID + "] has been created.");
103+
eventManager.startEvent(sEventID);
104+
System.out.println("Event [" + sEventID + "] has been started.");
105+
106+
eventManager.getStatus(aEventID);
107+
eventManager.getStatus(sEventID);
108+
109+
eventManager.stopEvent(aEventID);
110+
System.out.println("Event [" + aEventID + "] has been stopped.");
111+
eventManager.stopEvent(sEventID);
112+
System.out.println("Event [" + sEventID + "] has been stopped.");
113+
114+
} catch (MaxNumOfEventsAllowedException | LongRunningEventException | EventDoesNotExistException
115+
| InvalidOperationException e) {
116+
System.out.println(e.getMessage());
117+
}
118+
}
119+
120+
public void runInteractiveMode() {
121+
EventManager eventManager = new EventManager();
122+
123+
Scanner s = new Scanner(System.in);
124+
int option = 0;
125+
option = -1;
126+
while (option != 5) {
127+
System.out
128+
.println("(1) START_EVENT \n(2) STOP_EVENT \n(3) STATUS_OF_EVENT \n(4) STATUS_OF_ALL_EVENTS \n(5) EXIT");
129+
System.out.print("Choose [1,2,3,4,5]: ");
130+
option = s.nextInt();
131+
132+
if (option == 1) {
133+
s.nextLine();
134+
System.out.print("(A)sync or (S)ync event?: ");
135+
String eventType = s.nextLine();
136+
System.out.print("How long should this event run for (in seconds)?: ");
137+
int eventTime = s.nextInt();
138+
if (eventType.equalsIgnoreCase("A")) {
139+
try {
140+
int eventID = eventManager.createAsyncEvent(eventTime);
141+
System.out.println("Event [" + eventID + "] has been created.");
142+
eventManager.startEvent(eventID);
143+
System.out.println("Event [" + eventID + "] has been started.");
144+
} catch (MaxNumOfEventsAllowedException | LongRunningEventException | EventDoesNotExistException e) {
145+
System.out.println(e.getMessage());
146+
}
147+
} else if (eventType.equalsIgnoreCase("S")) {
148+
try {
149+
int eventID = eventManager.createSyncEvent(eventTime);
150+
System.out.println("Event [" + eventID + "] has been created.");
151+
eventManager.startEvent(eventID);
152+
System.out.println("Event [" + eventID + "] has been started.");
153+
} catch (MaxNumOfEventsAllowedException | InvalidOperationException | LongRunningEventException
154+
| EventDoesNotExistException e) {
155+
System.out.println(e.getMessage());
156+
}
157+
} else {
158+
System.out.println("Unknown event type.");
159+
}
160+
} else if (option == 2) {
161+
System.out.print("Event ID: ");
162+
int eventID = s.nextInt();
163+
try {
164+
eventManager.stopEvent(eventID);
165+
System.out.println("Event [" + eventID + "] has been stopped.");
166+
} catch (EventDoesNotExistException e) {
167+
System.out.println(e.getMessage());
168+
}
169+
} else if (option == 3) {
170+
System.out.print("Event ID: ");
171+
int eventID = s.nextInt();
172+
try {
173+
eventManager.getStatus(eventID);
174+
} catch (EventDoesNotExistException e) {
175+
System.out.println(e.getMessage());
176+
}
177+
} else if (option == 4) {
178+
eventManager.getStatusOfAllEvents();
179+
}
180+
}
181+
182+
s.close();
183+
}
184+
185+
}

0 commit comments

Comments
 (0)