diff --git a/event-queue/README.md b/event-queue/README.md
new file mode 100644
index 000000000..35fdac45c
--- /dev/null
+++ b/event-queue/README.md
@@ -0,0 +1,29 @@
+---
+layout: pattern
+title: Event Queue
+folder: event-queue
+permalink: /patterns/event-queue/
+categories: Concurrency
+tags:
+ - Java
+ - Difficulty Intermediate
+ - Queue
+---
+
+## Intent
+Event Queue is a good pattern if You have a limited accesibility resource (for example:
+Audio or Database), but You need to handle all the requests that want to use that.
+It puts all the requests in a queue and process them asynchronously.
+Gives the resource for the event when it is the next in the queue and in same time
+removes it from the queue.
+
+
+
+## Applicability
+Use the Event Queue pattern when
+
+* You have a limited accesibility resource and the asynchronous process is acceptable to reach that
+
+## Credits
+
+* [Mihaly Kuprivecz - Event Queue] (http://gameprogrammingpatterns.com/event-queue.html)
diff --git a/event-queue/etc/Bass-Drum-1.aif b/event-queue/etc/Bass-Drum-1.aif
new file mode 100644
index 000000000..f1eae69db
Binary files /dev/null and b/event-queue/etc/Bass-Drum-1.aif differ
diff --git a/event-queue/etc/Bass-Drum-1.wav b/event-queue/etc/Bass-Drum-1.wav
new file mode 100644
index 000000000..566181d94
Binary files /dev/null and b/event-queue/etc/Bass-Drum-1.wav differ
diff --git a/event-queue/etc/Closed-Hi-Hat-1.aif b/event-queue/etc/Closed-Hi-Hat-1.aif
new file mode 100644
index 000000000..ac248e4f4
Binary files /dev/null and b/event-queue/etc/Closed-Hi-Hat-1.aif differ
diff --git a/event-queue/etc/Closed-Hi-Hat-1.wav b/event-queue/etc/Closed-Hi-Hat-1.wav
new file mode 100644
index 000000000..2320db510
Binary files /dev/null and b/event-queue/etc/Closed-Hi-Hat-1.wav differ
diff --git a/event-queue/etc/event-queue.urm.puml b/event-queue/etc/event-queue.urm.puml
new file mode 100644
index 000000000..e2aabee31
--- /dev/null
+++ b/event-queue/etc/event-queue.urm.puml
@@ -0,0 +1,26 @@
+@startuml
+package com.iluwatar.event.queue {
+ class App {
+ + App()
+ + getAudioStream(filePath : String) : AudioInputStream {static}
+ + main(args : String[]) {static}
+ }
+ class Audio {
+ - MAX_PENDING : int {static}
+ - headIndex : int {static}
+ - pendingAudio : PlayMessage[] {static}
+ - tailIndex : int {static}
+ - updateThread : Thread {static}
+ + Audio()
+ + init() {static}
+ + playSound(stream : AudioInputStream, volume : float) {static}
+ + stopService() {static}
+ + update() {static}
+ }
+ class PlayMessage {
+ ~ stream : AudioInputStream
+ ~ volume : float
+ + PlayMessage()
+ }
+}
+@enduml
\ No newline at end of file
diff --git a/event-queue/etc/model.png b/event-queue/etc/model.png
new file mode 100644
index 000000000..45620e6f6
Binary files /dev/null and b/event-queue/etc/model.png differ
diff --git a/event-queue/etc/model.ucls b/event-queue/etc/model.ucls
new file mode 100644
index 000000000..ed923014b
--- /dev/null
+++ b/event-queue/etc/model.ucls
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/event-queue/pom.xml b/event-queue/pom.xml
new file mode 100644
index 000000000..fc857b425
--- /dev/null
+++ b/event-queue/pom.xml
@@ -0,0 +1,43 @@
+
+
+
+ 4.0.0
+
+ java-design-patterns
+ com.iluwatar
+ 1.16.0-SNAPSHOT
+
+ event-queue
+
+
+ junit
+ junit
+ test
+
+
+
\ No newline at end of file
diff --git a/event-queue/src/main/java/com/iluwatar/event/queue/App.java b/event-queue/src/main/java/com/iluwatar/event/queue/App.java
new file mode 100644
index 000000000..ea107d6ca
--- /dev/null
+++ b/event-queue/src/main/java/com/iluwatar/event/queue/App.java
@@ -0,0 +1,59 @@
+/**
+ * The MIT License
+ * Copyright (c) 2014-2016 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.queue;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+
+import javax.sound.sampled.UnsupportedAudioFileException;
+
+/**
+ * Event or message queues provide an asynchronous communications protocol, meaning that the sender
+ * and receiver of the message do not need to interact with the message queue at the same time.
+ * Events or messages placed onto the queue are stored until the recipient retrieves them. Event
+ * or message queues have implicit or explicit limits on the size of data that may be transmitted
+ * in a single message and the number of messages that may remain outstanding on the queue.
+ * A queue stores a series of notifications or requests in first-in, first-out order.
+ * Sending a notification enqueues the request and returns. The request processor then processes
+ * items from the queue at a later time.
+ */
+public class App {
+ /**
+ * Program entry point.
+ *
+ * @param args command line args
+ * @throws IOException when there is a problem with the audio file loading
+ * @throws UnsupportedAudioFileException when the loaded audio file is unsupported
+ */
+ public static void main(String[] args) throws UnsupportedAudioFileException, IOException {
+ Audio.playSound(Audio.getAudioStream("./etc/Bass-Drum-1.wav"), -10.0f);
+ Audio.playSound(Audio.getAudioStream("./etc/Closed-Hi-Hat-1.wav"), -8.0f);
+
+ System.out.println("Press Enter key to stop the program...");
+ BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
+ br.read();
+ Audio.stopService();
+ }
+}
diff --git a/event-queue/src/main/java/com/iluwatar/event/queue/Audio.java b/event-queue/src/main/java/com/iluwatar/event/queue/Audio.java
new file mode 100644
index 000000000..f8f1b1e3c
--- /dev/null
+++ b/event-queue/src/main/java/com/iluwatar/event/queue/Audio.java
@@ -0,0 +1,169 @@
+/**
+ * The MIT License
+ * Copyright (c) 2014-2016 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.queue;
+
+import java.io.File;
+import java.io.IOException;
+
+import javax.sound.sampled.AudioInputStream;
+import javax.sound.sampled.AudioSystem;
+import javax.sound.sampled.Clip;
+import javax.sound.sampled.LineUnavailableException;
+import javax.sound.sampled.UnsupportedAudioFileException;
+
+/**
+ * This class implements the Event Queue pattern.
+ * @author mkuprivecz
+ *
+ */
+public class Audio {
+
+ private static final int MAX_PENDING = 16;
+
+ private static int headIndex;
+
+ private static int tailIndex;
+
+ private static Thread updateThread = null;
+
+ private static PlayMessage[] pendingAudio = new PlayMessage[MAX_PENDING];
+
+ /**
+ * This method stops the Update Method's thread.
+ */
+ public static synchronized void stopService() {
+ if (updateThread != null) {
+ updateThread.interrupt();
+ }
+ }
+
+ /**
+ * This method stops the Update Method's thread.
+ * @return boolean
+ */
+ public static synchronized boolean isServiceRunning() {
+ if (updateThread != null && updateThread.isAlive() ) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Starts the thread for the Update Method pattern if it was not started previously.
+ * Also when the thread is is ready initializes the indexes of the queue
+ */
+ public static void init() {
+ if (updateThread == null) {
+ updateThread = new Thread(new Runnable() {
+ public void run() {
+ while (!Thread.currentThread().isInterrupted()) {
+ Audio.update();
+ }
+ }
+ });
+ }
+ startThread();
+ }
+
+ /**
+ * This is a synchronized thread starter
+ */
+ public static synchronized void startThread() {
+ if (!updateThread.isAlive()) {
+ updateThread.start();
+ headIndex = 0;
+ tailIndex = 0;
+ }
+ }
+
+ /**
+ * This method adds a new audio into the queue.
+ * @param stream is the AudioInputStream for the method
+ * @param volume is the level of the audio's volume
+ */
+ public static void playSound(AudioInputStream stream, float volume) {
+ init();
+ // Walk the pending requests.
+ for (int i = headIndex; i != tailIndex; i = (i + 1) % MAX_PENDING) {
+ if (getPendingAudio()[i].getStream() == stream) {
+ // Use the larger of the two volumes.
+ getPendingAudio()[i].setVolume(Math.max(volume, getPendingAudio()[i].getVolume()));
+
+ // Don't need to enqueue.
+ return;
+ }
+ }
+ getPendingAudio()[tailIndex] = new PlayMessage(stream, volume);
+ tailIndex = (tailIndex + 1) % MAX_PENDING;
+ }
+
+ /**
+ * This method uses the Update Method pattern.
+ * It takes the audio from the queue and plays it
+ */
+ public static void update() {
+ // If there are no pending requests, do nothing.
+ if (headIndex == tailIndex) {
+ return;
+ }
+ Clip clip = null;
+ try {
+ AudioInputStream audioStream = getPendingAudio()[headIndex].getStream();
+ headIndex++;
+ clip = AudioSystem.getClip();
+ clip.open(audioStream);
+ clip.start();
+ } catch (LineUnavailableException e) {
+ System.err.println("Error occoured while loading the audio: The line is unavailable");
+ e.printStackTrace();
+ } catch (IOException e) {
+ System.err.println("Input/Output error while loading the audio");
+ e.printStackTrace();
+ } catch (IllegalArgumentException e) {
+ System.err.println("The system doesn't support the sound: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Returns the AudioInputStream of a file
+ * @param filePath is the path of the audio file
+ * @return AudioInputStream
+ * @throws UnsupportedAudioFileException when the audio file is not supported
+ * @throws IOException when the file is not readable
+ */
+ public static AudioInputStream getAudioStream(String filePath)
+ throws UnsupportedAudioFileException, IOException {
+ return AudioSystem.getAudioInputStream(new File(filePath).getAbsoluteFile());
+ }
+
+ /**
+ * Returns with the message array of the queue
+ * @return PlayMessage[]
+ */
+ public static PlayMessage[] getPendingAudio() {
+ return pendingAudio;
+ }
+
+}
diff --git a/event-queue/src/main/java/com/iluwatar/event/queue/PlayMessage.java b/event-queue/src/main/java/com/iluwatar/event/queue/PlayMessage.java
new file mode 100644
index 000000000..5ced2e3b3
--- /dev/null
+++ b/event-queue/src/main/java/com/iluwatar/event/queue/PlayMessage.java
@@ -0,0 +1,59 @@
+/**
+ * The MIT License
+ * Copyright (c) 2014-2016 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.queue;
+
+import javax.sound.sampled.AudioInputStream;
+
+/**
+ * The Event Queue's queue will store the instances of this class.
+ * @author mkuprivecz
+ *
+ */
+public class PlayMessage {
+
+ private AudioInputStream stream;
+
+ private float volume;
+
+ public PlayMessage(AudioInputStream stream, float volume) {
+ setStream(stream);
+ setVolume(volume);
+ }
+
+ public AudioInputStream getStream() {
+ return stream;
+ }
+
+ private void setStream(AudioInputStream stream) {
+ this.stream = stream;
+ }
+
+ public float getVolume() {
+ return volume;
+ }
+
+ public void setVolume(float volume) {
+ this.volume = volume;
+ }
+}
diff --git a/event-queue/src/test/java/com/iluwatar/event/queue/AudioTest.java b/event-queue/src/test/java/com/iluwatar/event/queue/AudioTest.java
new file mode 100644
index 000000000..8e31ec6c3
--- /dev/null
+++ b/event-queue/src/test/java/com/iluwatar/event/queue/AudioTest.java
@@ -0,0 +1,77 @@
+/**
+ * The MIT License
+ * Copyright (c) 2014-2016 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.queue;
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+
+import javax.sound.sampled.UnsupportedAudioFileException;
+
+import org.junit.Test;
+
+/**
+ * Testing the Audio service of the Queue
+ * @author mkuprivecz
+ *
+ */
+public class AudioTest {
+
+ /**
+ * Test here that the playSound method works correctly
+ * @throws UnsupportedAudioFileException when the audio file is not supported
+ * @throws IOException when the file is not readable
+ * @throws InterruptedException when the test is interrupted externally
+ */
+ @Test
+ public void testPlaySound() throws UnsupportedAudioFileException, IOException, InterruptedException {
+ Audio.playSound(Audio.getAudioStream("./etc/Bass-Drum-1.wav"), -10.0f);
+ // test that service is started
+ assertTrue(Audio.isServiceRunning());
+ // adding a small pause to be sure that the sound is ended
+ Thread.sleep(5000);
+ // test that service is finished
+ assertFalse(!Audio.isServiceRunning());
+ }
+
+ /**
+ * Test here that the Queue
+ * @throws UnsupportedAudioFileException when the audio file is not supported
+ * @throws IOException when the file is not readable
+ * @throws InterruptedException when the test is interrupted externally
+ */
+ @Test
+ public void testQueue() throws UnsupportedAudioFileException, IOException, InterruptedException {
+ Audio.playSound(Audio.getAudioStream("./etc/Bass-Drum-1.aif"), -10.0f);
+ Audio.playSound(Audio.getAudioStream("./etc/Bass-Drum-1.aif"), -10.0f);
+ Audio.playSound(Audio.getAudioStream("./etc/Bass-Drum-1.aif"), -10.0f);
+ assertTrue(Audio.getPendingAudio().length > 0);
+ // test that service is started
+ assertTrue(Audio.isServiceRunning());
+ // adding a small pause to be sure that the sound is ended
+ Thread.sleep(10000);
+ // test that service is finished
+ assertFalse(!Audio.isServiceRunning());
+ }
+
+}
diff --git a/pom.xml b/pom.xml
index a45f0e1f3..d49a5aa24 100644
--- a/pom.xml
+++ b/pom.xml
@@ -122,7 +122,7 @@
factory-kit
feature-toggle
value-object
- module
+ module
monad
mute-idiom
mutex
@@ -133,6 +133,7 @@
promise
page-object
event-asynchronous
+ event-queue
queue-load-leveling
object-mother
data-bus
@@ -302,23 +303,23 @@
-
-
- com.github.markusmo3.urm
-
-
- urm-maven-plugin
-
-
- [1.4.1,)
-
-
- map
-
-
-
-
-
+
+
+ com.github.markusmo3.urm
+
+
+ urm-maven-plugin
+
+
+ [1.4.1,)
+
+
+ map
+
+
+
+
+