From 079f2ec5dddfac298436052c2761a29153f09d59 Mon Sep 17 00:00:00 2001 From: Caleb Brinkman Date: Mon, 30 Nov 2015 12:12:21 -0600 Subject: [PATCH 01/20] CI Output Test --- src/test/groovy/com/jenjinstudios/io/server/ServerSpec.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/groovy/com/jenjinstudios/io/server/ServerSpec.groovy b/src/test/groovy/com/jenjinstudios/io/server/ServerSpec.groovy index 3fc8f88..3f20000 100644 --- a/src/test/groovy/com/jenjinstudios/io/server/ServerSpec.groovy +++ b/src/test/groovy/com/jenjinstudios/io/server/ServerSpec.groovy @@ -98,7 +98,7 @@ public class ServerSpec extends Specification { given: "A ServerSocket which returns a mocked connection" def serverSocket = Mock(ServerSocket) def socket = Mock(Socket) - serverSocket.accept() >>> [socket, { while (true); }] + serverSocket.accept() >> socket >> {while(true) {}; null } def connection = Mock(Connection) def connectionBuilder = Mock(MultiConnectionBuilder) connectionBuilder.build(socket) >> connection From e653fe934ea26cdfb604b562e91a1415a301a07d Mon Sep 17 00:00:00 2001 From: Caleb Brinkman Date: Mon, 30 Nov 2015 12:27:53 -0600 Subject: [PATCH 02/20] Fix infinte loop --- src/test/groovy/com/jenjinstudios/io/server/ServerSpec.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/groovy/com/jenjinstudios/io/server/ServerSpec.groovy b/src/test/groovy/com/jenjinstudios/io/server/ServerSpec.groovy index 3f20000..f74b671 100644 --- a/src/test/groovy/com/jenjinstudios/io/server/ServerSpec.groovy +++ b/src/test/groovy/com/jenjinstudios/io/server/ServerSpec.groovy @@ -98,7 +98,7 @@ public class ServerSpec extends Specification { given: "A ServerSocket which returns a mocked connection" def serverSocket = Mock(ServerSocket) def socket = Mock(Socket) - serverSocket.accept() >> socket >> {while(true) {}; null } + serverSocket.accept() >>> [socket, {while(true);}] def connection = Mock(Connection) def connectionBuilder = Mock(MultiConnectionBuilder) connectionBuilder.build(socket) >> connection From ea4a81333edfd7d89bd7f3bf06042073846b3fc8 Mon Sep 17 00:00:00 2001 From: Caleb Brinkman Date: Mon, 30 Nov 2015 12:45:16 -0600 Subject: [PATCH 03/20] Output test two, electric boogaloo --- src/test/groovy/com/jenjinstudios/io/server/ServerSpec.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/groovy/com/jenjinstudios/io/server/ServerSpec.groovy b/src/test/groovy/com/jenjinstudios/io/server/ServerSpec.groovy index f74b671..cc87f9d 100644 --- a/src/test/groovy/com/jenjinstudios/io/server/ServerSpec.groovy +++ b/src/test/groovy/com/jenjinstudios/io/server/ServerSpec.groovy @@ -98,7 +98,7 @@ public class ServerSpec extends Specification { given: "A ServerSocket which returns a mocked connection" def serverSocket = Mock(ServerSocket) def socket = Mock(Socket) - serverSocket.accept() >>> [socket, {while(true);}] + serverSocket.accept() >>> [socket, {while(true){Thread.sleep(10)}; null}] def connection = Mock(Connection) def connectionBuilder = Mock(MultiConnectionBuilder) connectionBuilder.build(socket) >> connection From 6ad43d1c276d7eeb602189dd1bf683c3e313d03c Mon Sep 17 00:00:00 2001 From: Caleb Brinkman Date: Wed, 2 Dec 2015 13:33:27 -0600 Subject: [PATCH 04/20] Test CI output for blocking interaction --- src/test/groovy/com/jenjinstudios/io/server/ServerSpec.groovy | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/groovy/com/jenjinstudios/io/server/ServerSpec.groovy b/src/test/groovy/com/jenjinstudios/io/server/ServerSpec.groovy index cc87f9d..2bd333a 100644 --- a/src/test/groovy/com/jenjinstudios/io/server/ServerSpec.groovy +++ b/src/test/groovy/com/jenjinstudios/io/server/ServerSpec.groovy @@ -98,7 +98,7 @@ public class ServerSpec extends Specification { given: "A ServerSocket which returns a mocked connection" def serverSocket = Mock(ServerSocket) def socket = Mock(Socket) - serverSocket.accept() >>> [socket, {while(true){Thread.sleep(10)}; null}] + serverSocket.accept() >>> [socket, {Thread.sleep(10000); null}] def connection = Mock(Connection) def connectionBuilder = Mock(MultiConnectionBuilder) connectionBuilder.build(socket) >> connection @@ -170,4 +170,4 @@ public class ServerSpec extends Specification { 1 * connection1.sendMessage(message) 1 * connection2.sendMessage(message) } -} \ No newline at end of file +} From 31f3e9eba3d0c2484d6a193ee9836dfe7e05ca2c Mon Sep 17 00:00:00 2001 From: Caleb Brinkman Date: Tue, 1 Dec 2015 13:23:23 -0600 Subject: [PATCH 05/20] Add Authenticator, AuthenticationException --- .../AuthenticationException.java | 17 ++ .../io/authentication/Authenticator.java | 166 ++++++++++++++++++ 2 files changed, 183 insertions(+) create mode 100644 src/main/java/com/jenjinstudios/io/authentication/AuthenticationException.java create mode 100644 src/main/java/com/jenjinstudios/io/authentication/Authenticator.java diff --git a/src/main/java/com/jenjinstudios/io/authentication/AuthenticationException.java b/src/main/java/com/jenjinstudios/io/authentication/AuthenticationException.java new file mode 100644 index 0000000..cca745a --- /dev/null +++ b/src/main/java/com/jenjinstudios/io/authentication/AuthenticationException.java @@ -0,0 +1,17 @@ +package com.jenjinstudios.io.authentication; + +/** + * Thrown when there is an unexpected error while authenticating. + * + * @author Caleb Brinkman + */ +public class AuthenticationException extends Exception +{ + /** + * Construct a new AuthenticationException with the given message and cause. + * + * @param message The message. + * @param cause The cause. + */ + public AuthenticationException(String message, Throwable cause) { super(message, cause); } +} diff --git a/src/main/java/com/jenjinstudios/io/authentication/Authenticator.java b/src/main/java/com/jenjinstudios/io/authentication/Authenticator.java new file mode 100644 index 0000000..9c99a29 --- /dev/null +++ b/src/main/java/com/jenjinstudios/io/authentication/Authenticator.java @@ -0,0 +1,166 @@ +package com.jenjinstudios.io.authentication; + +import com.jenjinstudios.io.ExecutionContext; + +import java.util.Collections; +import java.util.Map; + +/** + * Interface defining several methods that are useful for authentication. + * + * @author Caleb Brinkman + */ +public interface Authenticator +{ + /** This constant is provided an a convenience, to specify a "password" credential in a {@code Map}. */ + String PASSWORD = "jio-password"; + /** This constant is provided an a convenience, to specify a "verification code" credential in a {@code Map}. */ + String VERIFICATION_CODE = "jio-verification-code"; + + /** + * Determine whether the user specified by the given unique identifier is authenticated. Behavior when the user + * doesn't exist is implementation-dependent. + * + * @param id The unique user identifier. + * + * @return Whether the user is authenticated. + * + * @throws AuthenticationException If there is an exception when determining authentication status. + */ + boolean isAuthenticated(String id) throws AuthenticationException; + + /** + * Determine whether the user specified by the given unique identifier exists. + * + * @param id The unique identifier of the user. + * + * @return Whether the user with the given identifier exists. + * + * @throws AuthenticationException If there is an exception when determining if the user exists/ + */ + boolean userExists(String id) throws AuthenticationException; + + /** + * Determine whether the given credentials are valid for the user with the specified unique identifier. Behavior + * when the user doesn't exist is implementation-dependent. + * + * @param id The unique user identifier. + * @param credentials A map of credentials containing key-value pairs, where the key is the name of + * credential and the value is the plaintext credential. Several constants that may be helpful key + * choices are provided by this interface. + * + * @return Whether the given credentials are valid. + * + * @throws AuthenticationException If there is an exception when determining the validity of the credentials. + */ + boolean credentialsValid(String id, Map credentials) throws AuthenticationException; + + /** + * Determine whether the given password is valid. By default, this method assumes that the {@link #PASSWORD} + * constant is the key used for storing passwords in the credentials Map. + * + * @param id The unique user identifier. + * @param password The plaintext password. + * + * @return Whether the password is valid. + * + * @throws AuthenticationException If there is an exception when determining password validity. + */ + default boolean passwordValid(String id, String password) throws AuthenticationException { + return credentialsValid(id, Collections.singletonMap(PASSWORD, password)); + } + + /** + * Authenticate the user with the given unique id and valid credentials and, if successful, populating the given + * ExecutionContext with the user data from the backing data store. By default, this method behaves in the + * following fashion: + *
+     * {@code boolean canLogin =
+     *       this.userExists(id) && !this.isAuthenticated(id) && this.credentialsValid(id,credentials);
+     *   if (canLogin) {
+     *       populate(context, id);
+     *   }
+     *   return canLogin;
+     * }
+     * 
+ * + * @param context The context to be populated with user data if authentication is successful. This object + * should not be modified if the authentication was unsuccessful. + * @param id The unique user identifier. + * @param credentials A map of credentials containing key-value pairs, where the key is the name of + * credential and the value is the plaintext credential. Several constants that may be helpful key + * choices are provided by this interface. + * + * @return Whether the user was successfully authenticated. If the user was not successfully authenticated, it is + * imperative that the {@code context} parameter not be modified. + * + * @throws AuthenticationException If there is an exception when authenticating the user. + */ + default boolean authenticate(T context, String id, Map credentials) throws AuthenticationException { + boolean canLogin = this.userExists(id) && !this.isAuthenticated(id) && this.credentialsValid(id, credentials); + if (canLogin) { + populate(context, id); + } + return canLogin; + } + + /** + * Authenticate the user with the given unique id and valid password and, if successful, populating the given + * ExecutionContext with the user data from the backing data store. By default, this method assumes that the + * {@link #PASSWORD} constant is the key used for storing passwords in the credentials Map. + * + * @param context The context to be populated with user data if authentication is successful. This object + * should not be modified if the authentication was unsuccessful. + * @param id The unique user identifier. + * @param password The plaintext password. + * + * @return Whether the user was successfully authenticated. If the user was not successfully authenticated, it is + * imperative that the {@code context} parameter not be modified. + * + * @throws AuthenticationException If there is an exception when authenticating the user. + */ + default boolean authenticate(T context, String id, String password) throws AuthenticationException { + return authenticate(context, id, Collections.singletonMap(PASSWORD, password)); + } + + /** + * Unauthenticate the user with the given unique id, restoring the given context to an unauthenticated state. + * + * @param context The context for the user to be unauthenticated; should + * @param id The unique user identifier. + * + * @return Whether the user was successfully unauthenticated and the context was modified. + * + * @throws AuthenticationException If there is an exception during unauthentication. + */ + boolean unauthenticate(T context, String id) throws AuthenticationException; + + /** + * Populate the given ExecutionContext with data for the user with the given unique identifier. + *

+ *

+ * Note: This method should not attempt any sort of authentication; credentials are not provided, it exists + * for the sole purpose of retrieving and populating user data. For authentication, use the {@link + * #credentialsValid(String, Map)}, {@link #authenticate(ExecutionContext, String, Map)}, and {@link + * #authenticate(ExecutionContext, String, String)} methods. + *
+ * + * @param context The context to populate with user data. + * @param id The unique user identifier. + * + * @throws AuthenticationException If there is an exception when populating the user data. + */ + void populate(T context, String id) throws AuthenticationException; + + /** + * Update the backing data store, for the user with the given id, with data from the given context. + * + * @param context The context containing data to be placed in the backing data store. + * @param id The unique user id. + * + * @return {@code true} If the update was successful and the backing data store was modified. + * + * @throws AuthenticationException If there is an exception during the update. + */ + boolean update(T context, String id) throws AuthenticationException; +} From 69cd16aa43c2402a610cacfe30c4af15b6b5bf74 Mon Sep 17 00:00:00 2001 From: Caleb Brinkman Date: Tue, 1 Dec 2015 13:47:21 -0600 Subject: [PATCH 06/20] Remove default for authenticate --- .../io/authentication/Authenticator.java | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/jenjinstudios/io/authentication/Authenticator.java b/src/main/java/com/jenjinstudios/io/authentication/Authenticator.java index 9c99a29..e9d9eed 100644 --- a/src/main/java/com/jenjinstudios/io/authentication/Authenticator.java +++ b/src/main/java/com/jenjinstudios/io/authentication/Authenticator.java @@ -72,8 +72,7 @@ default boolean passwordValid(String id, String password) throws AuthenticationE /** * Authenticate the user with the given unique id and valid credentials and, if successful, populating the given - * ExecutionContext with the user data from the backing data store. By default, this method behaves in the - * following fashion: + * ExecutionContext with the user data from the backing data store. A suggested method behavior is: *
      * {@code boolean canLogin =
      *       this.userExists(id) && !this.isAuthenticated(id) && this.credentialsValid(id,credentials);
@@ -96,13 +95,7 @@ default boolean passwordValid(String id, String password) throws AuthenticationE
      *
      * @throws AuthenticationException If there is an exception when authenticating the user.
      */
-    default boolean authenticate(T context, String id, Map credentials) throws AuthenticationException {
-        boolean canLogin = this.userExists(id) && !this.isAuthenticated(id) && this.credentialsValid(id, credentials);
-        if (canLogin) {
-            populate(context, id);
-        }
-        return canLogin;
-    }
+    boolean authenticate(T context, String id, Map credentials) throws AuthenticationException;
 
     /**
      * Authenticate the user with the given unique id and valid password and, if successful, populating the given

From b5f7df4952cbd1bcaecead01a160085bbd22a043 Mon Sep 17 00:00:00 2001
From: Caleb Brinkman 
Date: Wed, 2 Dec 2015 13:43:17 -0600
Subject: [PATCH 07/20] Increase wait time

CI continues to display unnecessary warning messages
---
 src/test/groovy/com/jenjinstudios/io/server/ServerSpec.groovy | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/test/groovy/com/jenjinstudios/io/server/ServerSpec.groovy b/src/test/groovy/com/jenjinstudios/io/server/ServerSpec.groovy
index 2bd333a..25b067c 100644
--- a/src/test/groovy/com/jenjinstudios/io/server/ServerSpec.groovy
+++ b/src/test/groovy/com/jenjinstudios/io/server/ServerSpec.groovy
@@ -98,7 +98,7 @@ public class ServerSpec extends Specification {
         given: "A ServerSocket which returns a mocked connection"
             def serverSocket = Mock(ServerSocket)
             def socket = Mock(Socket)
-            serverSocket.accept() >>> [socket, {Thread.sleep(10000); null}]
+            serverSocket.accept() >>> [socket, {Thread.sleep(100000); null}]
             def connection = Mock(Connection)
             def connectionBuilder = Mock(MultiConnectionBuilder)
             connectionBuilder.build(socket) >> connection

From e49be386081906be8c886b41537e57f4de1c7bdd Mon Sep 17 00:00:00 2001
From: Caleb Brinkman 
Date: Wed, 2 Dec 2015 13:56:38 -0600
Subject: [PATCH 08/20] Another CI output test

---
 .../groovy/com/jenjinstudios/io/server/ServerSpec.groovy  | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/src/test/groovy/com/jenjinstudios/io/server/ServerSpec.groovy b/src/test/groovy/com/jenjinstudios/io/server/ServerSpec.groovy
index 25b067c..e40071e 100644
--- a/src/test/groovy/com/jenjinstudios/io/server/ServerSpec.groovy
+++ b/src/test/groovy/com/jenjinstudios/io/server/ServerSpec.groovy
@@ -98,7 +98,7 @@ public class ServerSpec extends Specification {
         given: "A ServerSocket which returns a mocked connection"
             def serverSocket = Mock(ServerSocket)
             def socket = Mock(Socket)
-            serverSocket.accept() >>> [socket, {Thread.sleep(100000); null}]
+            serverSocket.accept() >>> [socket, { block() }]
             def connection = Mock(Connection)
             def connectionBuilder = Mock(MultiConnectionBuilder)
             connectionBuilder.build(socket) >> connection
@@ -170,4 +170,10 @@ public class ServerSpec extends Specification {
             1 * connection1.sendMessage(message)
             1 * connection2.sendMessage(message)
     }
+
+    def block() {
+        println 'Blocking'
+        Thread.sleep(100000)
+        return null
+    }
 }

From 0e6488c75f7becfc37eaf845c0e8490ee0e795aa Mon Sep 17 00:00:00 2001
From: Caleb Brinkman 
Date: Wed, 2 Dec 2015 14:54:33 -0600
Subject: [PATCH 09/20] Yet another CI output test

---
 .../groovy/com/jenjinstudios/io/server/ServerSpec.groovy | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/src/test/groovy/com/jenjinstudios/io/server/ServerSpec.groovy b/src/test/groovy/com/jenjinstudios/io/server/ServerSpec.groovy
index e40071e..b5bd5b7 100644
--- a/src/test/groovy/com/jenjinstudios/io/server/ServerSpec.groovy
+++ b/src/test/groovy/com/jenjinstudios/io/server/ServerSpec.groovy
@@ -98,7 +98,7 @@ public class ServerSpec extends Specification {
         given: "A ServerSocket which returns a mocked connection"
             def serverSocket = Mock(ServerSocket)
             def socket = Mock(Socket)
-            serverSocket.accept() >>> [socket, { block() }]
+            serverSocket.accept() >> { args -> socket } >> m_block
             def connection = Mock(Connection)
             def connectionBuilder = Mock(MultiConnectionBuilder)
             connectionBuilder.build(socket) >> connection
@@ -171,9 +171,8 @@ public class ServerSpec extends Specification {
             1 * connection2.sendMessage(message)
     }
 
-    def block() {
-        println 'Blocking'
-        Thread.sleep(100000)
-        return null
+    def m_block = {
+        Thread.sleep(10000)
+        null;
     }
 }

From 057912cc5f8c59c4aae85186b1d01278da597626 Mon Sep 17 00:00:00 2001
From: Caleb Brinkman 
Date: Wed, 2 Dec 2015 15:43:05 -0600
Subject: [PATCH 10/20] What even

---
 .../groovy/com/jenjinstudios/io/server/ServerSpec.groovy     | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/src/test/groovy/com/jenjinstudios/io/server/ServerSpec.groovy b/src/test/groovy/com/jenjinstudios/io/server/ServerSpec.groovy
index b5bd5b7..8c09ba6 100644
--- a/src/test/groovy/com/jenjinstudios/io/server/ServerSpec.groovy
+++ b/src/test/groovy/com/jenjinstudios/io/server/ServerSpec.groovy
@@ -171,8 +171,5 @@ public class ServerSpec extends Specification {
             1 * connection2.sendMessage(message)
     }
 
-    def m_block = {
-        Thread.sleep(10000)
-        null;
-    }
+    def m_block = {}
 }

From 20c91064392cd5951268c6745e552ff114d672fc Mon Sep 17 00:00:00 2001
From: Caleb Brinkman 
Date: Wed, 2 Dec 2015 16:02:20 -0600
Subject: [PATCH 11/20] Last attempt

---
 src/test/groovy/com/jenjinstudios/io/server/ServerSpec.groovy | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/test/groovy/com/jenjinstudios/io/server/ServerSpec.groovy b/src/test/groovy/com/jenjinstudios/io/server/ServerSpec.groovy
index 8c09ba6..798c5aa 100644
--- a/src/test/groovy/com/jenjinstudios/io/server/ServerSpec.groovy
+++ b/src/test/groovy/com/jenjinstudios/io/server/ServerSpec.groovy
@@ -171,5 +171,5 @@ public class ServerSpec extends Specification {
             1 * connection2.sendMessage(message)
     }
 
-    def m_block = {}
+    def m_block = { while (true); }
 }

From d517103833cd26d7b644f8b9a7cf345434042d65 Mon Sep 17 00:00:00 2001
From: Caleb Brinkman 
Date: Wed, 2 Dec 2015 18:51:50 -0600
Subject: [PATCH 12/20] Bump to 0.2.0-alpha

---
 build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/build.gradle b/build.gradle
index 326321a..3523c1c 100644
--- a/build.gradle
+++ b/build.gradle
@@ -14,7 +14,7 @@ plugins {
 
 description = 'Jenjin Core IO API'
 group = 'com.jenjinstudios'
-version = '0.1.0-alpha'
+version = '0.2.0-alpha'
 
 // Core plugins
 apply plugin: 'java'

From 575cde12c03c987886343dd791cf95d1e4230746 Mon Sep 17 00:00:00 2001
From: Caleb Brinkman 
Date: Wed, 2 Dec 2015 18:50:01 -0600
Subject: [PATCH 13/20] Add new constructor

---
 .../io/authentication/AuthenticationException.java          | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/src/main/java/com/jenjinstudios/io/authentication/AuthenticationException.java b/src/main/java/com/jenjinstudios/io/authentication/AuthenticationException.java
index cca745a..6db55e7 100644
--- a/src/main/java/com/jenjinstudios/io/authentication/AuthenticationException.java
+++ b/src/main/java/com/jenjinstudios/io/authentication/AuthenticationException.java
@@ -14,4 +14,10 @@ public class AuthenticationException extends Exception
      * @param cause The cause.
      */
     public AuthenticationException(String message, Throwable cause) { super(message, cause); }
+
+    /**
+     * Construct a new AuthenticationException with the given message.
+     * @param message The message.
+     */
+    public AuthenticationException(String message) {super(message);}
 }

From 743d09ab47aa63bb377be49ede455fb770cbf6a8 Mon Sep 17 00:00:00 2001
From: Caleb Brinkman 
Date: Wed, 2 Dec 2015 18:51:50 -0600
Subject: [PATCH 14/20] Bump to 0.2.0-alpha

---
 build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/build.gradle b/build.gradle
index 326321a..3523c1c 100644
--- a/build.gradle
+++ b/build.gradle
@@ -14,7 +14,7 @@ plugins {
 
 description = 'Jenjin Core IO API'
 group = 'com.jenjinstudios'
-version = '0.1.0-alpha'
+version = '0.2.0-alpha'
 
 // Core plugins
 apply plugin: 'java'

From 16b4b66a78f5ca9059f9f3d0a782440da81bab8b Mon Sep 17 00:00:00 2001
From: Caleb Brinkman 
Date: Tue, 8 Dec 2015 08:33:02 -0600
Subject: [PATCH 15/20] Add close method to Authenticator

---
 .../com/jenjinstudios/io/authentication/Authenticator.java | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/src/main/java/com/jenjinstudios/io/authentication/Authenticator.java b/src/main/java/com/jenjinstudios/io/authentication/Authenticator.java
index e9d9eed..7ea708a 100644
--- a/src/main/java/com/jenjinstudios/io/authentication/Authenticator.java
+++ b/src/main/java/com/jenjinstudios/io/authentication/Authenticator.java
@@ -156,4 +156,11 @@ default boolean authenticate(T context, String id, String password) throws Authe
      * @throws AuthenticationException If there is an exception during the update.
      */
     boolean update(T context, String id) throws AuthenticationException;
+
+    /**
+     * Close the backing database connection.
+     *
+     * @throws AuthenticationException If there is an exception when closing the backing database connection.
+     */
+    void close() throws AuthenticationException;
 }

From ed22f6a20db7404e8e323bfc448d41c83268dd00 Mon Sep 17 00:00:00 2001
From: Caleb Brinkman 
Date: Tue, 15 Dec 2015 13:24:34 -0600
Subject: [PATCH 16/20] Add extra log statement to ErrorTask

---
 src/main/java/com/jenjinstudios/io/concurrency/ErrorTask.java | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/main/java/com/jenjinstudios/io/concurrency/ErrorTask.java b/src/main/java/com/jenjinstudios/io/concurrency/ErrorTask.java
index d64d88e..9ed20df 100644
--- a/src/main/java/com/jenjinstudios/io/concurrency/ErrorTask.java
+++ b/src/main/java/com/jenjinstudios/io/concurrency/ErrorTask.java
@@ -36,6 +36,7 @@ public void run() {
             } else {
                 LOGGER.warn("Encountered error from MessageQueue", t);
             }
+            LOGGER.debug("Invoking error callback function");
             errorCallback.accept(t);
         });
     }

From e9b5c3c45ea6c90334de7383f354fa470369093c Mon Sep 17 00:00:00 2001
From: Caleb Brinkman 
Date: Tue, 15 Dec 2015 13:31:11 -0600
Subject: [PATCH 17/20] Add logging to ExecutionTask

---
 .../jenjinstudios/io/concurrency/ExecutionTask.java | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/src/main/java/com/jenjinstudios/io/concurrency/ExecutionTask.java b/src/main/java/com/jenjinstudios/io/concurrency/ExecutionTask.java
index d5d292d..76effd0 100644
--- a/src/main/java/com/jenjinstudios/io/concurrency/ExecutionTask.java
+++ b/src/main/java/com/jenjinstudios/io/concurrency/ExecutionTask.java
@@ -2,6 +2,8 @@
 
 import com.jenjinstudios.io.ExecutionContext;
 import com.jenjinstudios.io.Message;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import java.util.Collection;
 import java.util.List;
@@ -14,6 +16,7 @@
  */
 public class ExecutionTask implements Runnable
 {
+    private static final Logger LOGGER = LoggerFactory.getLogger(ExecutionTask.class);
     private final MessageQueue messageQueue;
     private final T executionContext;
     private final Collection> contextualTasks;
@@ -36,11 +39,19 @@ public ExecutionTask(MessageQueue messageQueue, T executionContext, Collection incoming = messageQueue.getIncomingAndClear();
         incoming.forEach(message -> {
+            if (LOGGER.isDebugEnabled()) {
+                LOGGER.debug("Executing message (Type: {})", message.getClass().getName());
+            }
             Message response = message.execute(executionContext);
             if (response != null) {
                 messageQueue.queueOutgoing(response);
             }
-            contextualTasks.forEach(consumer -> consumer.accept(executionContext));
+            contextualTasks.forEach(consumer -> {
+                if (LOGGER.isDebugEnabled()) {
+                    LOGGER.debug("Executing contextual task: {}", consumer);
+                }
+                consumer.accept(executionContext);
+            });
         });
     }
 }

From a2d6c235a6414ef6aca84fbedc5275cb87853769 Mon Sep 17 00:00:00 2001
From: Caleb Brinkman 
Date: Tue, 15 Dec 2015 13:32:42 -0600
Subject: [PATCH 18/20] Add new log statement to ReadTask

---
 src/main/java/com/jenjinstudios/io/concurrency/ReadTask.java | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/main/java/com/jenjinstudios/io/concurrency/ReadTask.java b/src/main/java/com/jenjinstudios/io/concurrency/ReadTask.java
index c62c419..fd5920f 100644
--- a/src/main/java/com/jenjinstudios/io/concurrency/ReadTask.java
+++ b/src/main/java/com/jenjinstudios/io/concurrency/ReadTask.java
@@ -36,6 +36,9 @@ public void run() {
         try {
             if (noError) {
                 final Message message = messageReader.read();
+                if (LOGGER.isDebugEnabled()) {
+                    LOGGER.debug("Read Message (Type: {})", message.getClass().getName());
+                }
                 messageQueue.messageReceived(message);
             }
         } catch (IOException e) {

From af681a410edc09b9c8546e1e8a0ffe3c3be5c415 Mon Sep 17 00:00:00 2001
From: Caleb Brinkman 
Date: Tue, 15 Dec 2015 13:38:49 -0600
Subject: [PATCH 19/20] Add log statement to WriteTask

---
 src/main/java/com/jenjinstudios/io/concurrency/WriteTask.java | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/main/java/com/jenjinstudios/io/concurrency/WriteTask.java b/src/main/java/com/jenjinstudios/io/concurrency/WriteTask.java
index 7829567..25ff286 100644
--- a/src/main/java/com/jenjinstudios/io/concurrency/WriteTask.java
+++ b/src/main/java/com/jenjinstudios/io/concurrency/WriteTask.java
@@ -35,6 +35,9 @@ public void run() {
         final List outgoing = messageQueue.getOutgoingAndClear();
         outgoing.forEach(message -> {
             try {
+                if (LOGGER.isDebugEnabled()) {
+                    LOGGER.debug("Attempting to write message.  (Type: {})" + message.getClass().getName());
+                }
                 messageWriter.write(message);
             } catch (IOException e) {
                 messageQueue.errorEncountered(e);

From 9bb44613eb684b762ae0be4614c6486be225a40e Mon Sep 17 00:00:00 2001
From: Caleb Brinkman 
Date: Tue, 15 Dec 2015 15:24:00 -0600
Subject: [PATCH 20/20] Bump to 0.3.0-alpha

---
 build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/build.gradle b/build.gradle
index 3523c1c..c94a657 100644
--- a/build.gradle
+++ b/build.gradle
@@ -14,7 +14,7 @@ plugins {
 
 description = 'Jenjin Core IO API'
 group = 'com.jenjinstudios'
-version = '0.2.0-alpha'
+version = '0.3.0-alpha'
 
 // Core plugins
 apply plugin: 'java'