From 3252f07e22feec458c06c6334fecad79eeaeaff3 Mon Sep 17 00:00:00 2001 From: Tommy Gomez Date: Fri, 17 Jul 2020 19:22:28 +0000 Subject: [PATCH 01/24] change MessageUpdate to use synchronization --- src/main/java/shef/data/MessageUpdate.java | 26 +++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/main/java/shef/data/MessageUpdate.java b/src/main/java/shef/data/MessageUpdate.java index 63baa4d..53d545d 100644 --- a/src/main/java/shef/data/MessageUpdate.java +++ b/src/main/java/shef/data/MessageUpdate.java @@ -18,4 +18,28 @@ public class MessageUpdate extends Observable { -} \ No newline at end of file +/** + * Handles incoming messages and distributes them to waiting MessagePromises. + * The methods are synchronized to allow only one thread to modify and send a message at a time. + * This prevents race conditions where two users post a new message simultaneously, which could allow + * a message to be changed and lost before it is sent. + */ +public class MessageUpdate extends Observable { + + private String message; + + public MessageUpdate() { + this.message = null; + } + + /** Sends the message to waiting observers via notifyObservers(). */ + public synchronized void sendMessage() { + notifyObservers(message); + } + + /** Set the message and mark the MessageUpdate as changed. */ + public synchronized void setMessage(String message) { + this.message = message; + setChanged(); + } +} From 881b943ca25fa12715a6bbace2d0608ce7c0205a Mon Sep 17 00:00:00 2001 From: Tommy Gomez Date: Thu, 16 Jul 2020 20:47:04 +0000 Subject: [PATCH 02/24] fix error handling within Promise's catch --- src/main/webapp/script.js | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/main/webapp/script.js b/src/main/webapp/script.js index 47ca81f..79d95e2 100644 --- a/src/main/webapp/script.js +++ b/src/main/webapp/script.js @@ -38,3 +38,33 @@ function createCommentElement(comment) { function addParagraph(content) { return "

" + content + "

"; } + +function newGroupchat() { + const request = new Request("/load-groupchat", {method: 'POST'}); + fetch(request).then(response => response.text()).then((key) => { + redirectToGroupchat(key); + }); +} + +function loadGroupchat() { + const urlParams = new URLSearchParams(window.location.search); + const key = urlParams.get('key'); + fetch('/load-groupchat?key=' + key).then(response => response.json()) + .catch(error => { + alert('Error: Groupchat does not exist'); + window.location.href = 'index.html'; + }).then((messages) => { + const messageContainer = document.getElementById('messages'); + messageContainer.innerHTML = ''; + for (var i = 0; i < messages.length; i++) { + const message = document.createElement('p'); + message.innerText = messages[i]; + messageContainer.appendChild(message); + } + }); +} + +function redirectToGroupchat(keyParameter) { + const key = keyParameter ? keyParameter : document.getElementById('groupchat-key').value; + window.location.href = "/groupchat.html?key=" + key; +} From 001cfc2dcd37bf4cb55c592224ceae8d43cb4ddd Mon Sep 17 00:00:00 2001 From: Tommy Gomez Date: Thu, 16 Jul 2020 22:49:46 +0000 Subject: [PATCH 03/24] add form to groupchat.html to submit new messages --- src/main/webapp/groupchat.html | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/webapp/groupchat.html b/src/main/webapp/groupchat.html index 24e1803..fa867ad 100644 --- a/src/main/webapp/groupchat.html +++ b/src/main/webapp/groupchat.html @@ -10,5 +10,12 @@

Groupchat

+
+ +
+
+ + +
\ No newline at end of file From 772e2d0b894cbe00c6db1f3d98298951eb0e0d3d Mon Sep 17 00:00:00 2001 From: Tommy Gomez Date: Wed, 15 Jul 2020 19:41:12 +0000 Subject: [PATCH 04/24] add HTML pages for front end --- src/main/webapp/groupchat.html | 2 +- src/main/webapp/index.html | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 src/main/webapp/index.html diff --git a/src/main/webapp/groupchat.html b/src/main/webapp/groupchat.html index fa867ad..0a7f4e7 100644 --- a/src/main/webapp/groupchat.html +++ b/src/main/webapp/groupchat.html @@ -8,7 +8,7 @@ - +

Groupchat

diff --git a/src/main/webapp/index.html b/src/main/webapp/index.html new file mode 100644 index 0000000..edcde94 --- /dev/null +++ b/src/main/webapp/index.html @@ -0,0 +1,23 @@ + + + + + + + shef + + + + +

Groupchat Options

+

Create new groupchat

+

+ +

Load groupchat

+ +

+ + +
+ + \ No newline at end of file From 3c30a8d7cf90de2642fdba09338b872599b55c3d Mon Sep 17 00:00:00 2001 From: Tommy Gomez Date: Wed, 15 Jul 2020 19:41:32 +0000 Subject: [PATCH 05/24] add loading methods to javascript --- src/main/webapp/script.js | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/main/webapp/script.js b/src/main/webapp/script.js index 79d95e2..d28bfe3 100644 --- a/src/main/webapp/script.js +++ b/src/main/webapp/script.js @@ -1,6 +1,6 @@ // Copyright 2019 Google LLC // -// Licensed under the Apache License, Version 2.0 (the "License"); +// Licensed under the Apache License, Version 2.0 (the 'License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // @@ -49,19 +49,18 @@ function newGroupchat() { function loadGroupchat() { const urlParams = new URLSearchParams(window.location.search); const key = urlParams.get('key'); - fetch('/load-groupchat?key=' + key).then(response => response.json()) - .catch(error => { - alert('Error: Groupchat does not exist'); - window.location.href = 'index.html'; - }).then((messages) => { - const messageContainer = document.getElementById('messages'); - messageContainer.innerHTML = ''; - for (var i = 0; i < messages.length; i++) { - const message = document.createElement('p'); - message.innerText = messages[i]; - messageContainer.appendChild(message); - } - }); + fetch('/load-groupchat?key=' + key).then(response => response.json()).then((messages) => { + const messageContainer = document.getElementById('messages'); + messageContainer.innerHTML = ''; + for (var i = 0; i < messages.length; i++) { + const message = document.createElement('p'); + message.innerText = messages[i]; + messageContainer.appendChild(message); + } + }).catch(error => + alert('Error: Groupchat does not exist') + ); + } function redirectToGroupchat(keyParameter) { From 238b41ab6be6d15c37a64fe2f46b2724cdf02fa9 Mon Sep 17 00:00:00 2001 From: Tommy Gomez Date: Wed, 15 Jul 2020 19:00:33 +0000 Subject: [PATCH 06/24] create servlet to retrieve and post groupchats --- .../java/shef/servlets/GroupchatServlet.java | 34 +++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/src/main/java/shef/servlets/GroupchatServlet.java b/src/main/java/shef/servlets/GroupchatServlet.java index a7700ee..c9c4db5 100644 --- a/src/main/java/shef/servlets/GroupchatServlet.java +++ b/src/main/java/shef/servlets/GroupchatServlet.java @@ -17,23 +17,53 @@ import com.google.appengine.api.datastore.DatastoreService; import com.google.appengine.api.datastore.DatastoreServiceFactory; import com.google.appengine.api.datastore.Entity; +import com.google.appengine.api.datastore.Key; +import com.google.appengine.api.datastore.KeyFactory; +import com.google.appengine.api.datastore.EntityNotFoundException; +import com.google.gson.Gson; import java.io.IOException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import java.util.ArrayList; -@WebServlet("/groupchat") +@WebServlet("/load-groupchat") public class GroupchatServlet extends HttpServlet { + DatastoreService datastore; + + @Override + public void init() { + datastore = DatastoreServiceFactory.getDatastoreService(); + } + @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { + String keyString = request.getParameter("key"); + Entity groupchatEntity = null; + try { + groupchatEntity = datastore.get(KeyFactory.stringToKey(keyString)); + } catch (EntityNotFoundException e) { + e.printStackTrace(); + return; + } + ArrayList messages = (ArrayList) groupchatEntity.getProperty("messages"); + response.setContentType("application/json;"); + Gson gson = new Gson(); + response.getWriter().println(gson.toJson(messages)); } @Override public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException { - + Entity groupchat = new Entity("Groupchat"); + groupchat.setProperty("messages", new ArrayList()); + datastore.put(groupchat); + + response.setContentType("text/html"); + String groupchatKey = KeyFactory.keyToString(groupchat.getKey()); + response.getWriter().println(groupchatKey); } } From ba118ffb8fbd12cc7b6700559be55986110ba595 Mon Sep 17 00:00:00 2001 From: Tommy Gomez Date: Wed, 15 Jul 2020 23:17:29 +0000 Subject: [PATCH 07/24] add MessageUpdate instance to NewMessageServlet --- src/main/java/shef/servlets/NewMessageServlet.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main/java/shef/servlets/NewMessageServlet.java b/src/main/java/shef/servlets/NewMessageServlet.java index 1c8cc03..9c13ed4 100644 --- a/src/main/java/shef/servlets/NewMessageServlet.java +++ b/src/main/java/shef/servlets/NewMessageServlet.java @@ -22,9 +22,19 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import shef.data.MessageUpdate; @WebServlet("/new-message") public class NewMessageServlet extends HttpServlet { + + private MessageUpdate messageUpdate; + private DatastoreService datastore; + + @Override + public void init() { + messageUpdate = new MessageUpdate(); + datastore = DatastoreServiceFactory.getDatastoreService(); + } @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { From ee248f19daff87ce901e30064b94aad9714ea5b7 Mon Sep 17 00:00:00 2001 From: Tommy Gomez Date: Wed, 15 Jul 2020 23:17:55 +0000 Subject: [PATCH 08/24] implement MessageUpdate methods --- src/main/java/shef/data/MessageUpdate.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/shef/data/MessageUpdate.java b/src/main/java/shef/data/MessageUpdate.java index 53d545d..bf7e42d 100644 --- a/src/main/java/shef/data/MessageUpdate.java +++ b/src/main/java/shef/data/MessageUpdate.java @@ -16,8 +16,6 @@ import java.util.Observable; -public class MessageUpdate extends Observable { - /** * Handles incoming messages and distributes them to waiting MessagePromises. * The methods are synchronized to allow only one thread to modify and send a message at a time. From 2466a1d2e5f9644b9f8cc8ec2a324621f8501390 Mon Sep 17 00:00:00 2001 From: Tommy Gomez Date: Thu, 16 Jul 2020 01:06:31 +0000 Subject: [PATCH 09/24] implement MessagePromise --- src/main/java/shef/data/MessagePromise.java | 44 +++++++++++++++++++-- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/src/main/java/shef/data/MessagePromise.java b/src/main/java/shef/data/MessagePromise.java index 759ad21..0b4b2d9 100644 --- a/src/main/java/shef/data/MessagePromise.java +++ b/src/main/java/shef/data/MessagePromise.java @@ -16,11 +16,49 @@ import java.util.Observer; import java.util.Observable; +import shef.data.MessageUpdate; +/** + * Returns new messages to GET requests, blocking until they are received from the MessageUpdate. + * Each MessagePromise is used to get one message. + */ public class MessagePromise implements Observer { - public void update(Observable messageUpdate, Object newMessage) { - + private String message; + private boolean updated; + private MessageUpdate messageUpdate; + + public MessagePromise(MessageUpdate messageUpdate) { + this.message = null; + this.updated = false; + this.messageUpdate = messageUpdate; + this.messageUpdate.addObserver(this); } -} \ No newline at end of file + /** + * Gets the next message from the MessageUpdate. + * This method waits until it receives a new message from MessageUpdate. + * It then unblocks, and returns the message to the servlet. + */ + synchronized public String getNextMessage() { + // Ensure that the thread waits until an update is detected. + while (!updated) { + try { + wait(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + messageUpdate.deleteObserver(this); + return message; + } + + /** Receives a new message and then wakes the waiting thread with notify(). */ + @Override + synchronized public void update(Observable messageUpdate, Object message) { + this.message = (String) message; + this.updated = true; + notify(); + } +} From 3b1b0991cc8ca99776ba52a427fd4afdf43caf76 Mon Sep 17 00:00:00 2001 From: Tommy Gomez Date: Thu, 16 Jul 2020 23:23:31 +0000 Subject: [PATCH 10/24] servlet always returns ArrayList instance instead of null in case of empty list --- src/main/java/shef/servlets/GroupchatServlet.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/shef/servlets/GroupchatServlet.java b/src/main/java/shef/servlets/GroupchatServlet.java index c9c4db5..a60b39d 100644 --- a/src/main/java/shef/servlets/GroupchatServlet.java +++ b/src/main/java/shef/servlets/GroupchatServlet.java @@ -49,7 +49,8 @@ public void doGet(HttpServletRequest request, HttpServletResponse response) thro return; } - ArrayList messages = (ArrayList) groupchatEntity.getProperty("messages"); + Object messageObject = groupchatEntity.getProperty("messages"); + ArrayList messages = messageObject != null ? (ArrayList) messageObject : new ArrayList<>(); response.setContentType("application/json;"); Gson gson = new Gson(); response.getWriter().println(gson.toJson(messages)); From e07de5f6bb0d91f38371f03340cddd6320b05413 Mon Sep 17 00:00:00 2001 From: Tommy Gomez Date: Fri, 17 Jul 2020 19:46:08 +0000 Subject: [PATCH 11/24] change to public synchronized --- src/main/java/shef/data/MessagePromise.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/shef/data/MessagePromise.java b/src/main/java/shef/data/MessagePromise.java index 0b4b2d9..7633d61 100644 --- a/src/main/java/shef/data/MessagePromise.java +++ b/src/main/java/shef/data/MessagePromise.java @@ -40,7 +40,7 @@ public MessagePromise(MessageUpdate messageUpdate) { * This method waits until it receives a new message from MessageUpdate. * It then unblocks, and returns the message to the servlet. */ - synchronized public String getNextMessage() { + public synchronized String getNextMessage() { // Ensure that the thread waits until an update is detected. while (!updated) { try { @@ -56,7 +56,7 @@ synchronized public String getNextMessage() { /** Receives a new message and then wakes the waiting thread with notify(). */ @Override - synchronized public void update(Observable messageUpdate, Object message) { + public synchronized void update(Observable messageUpdate, Object message) { this.message = (String) message; this.updated = true; notify(); From 057d0e7dfe92d4e9b6038f9ffe5f2fef1bb55787 Mon Sep 17 00:00:00 2001 From: Tommy Gomez Date: Thu, 16 Jul 2020 20:47:04 +0000 Subject: [PATCH 12/24] fix error handling within Promise's catch --- src/main/webapp/script.js | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/main/webapp/script.js b/src/main/webapp/script.js index d28bfe3..5a9f6df 100644 --- a/src/main/webapp/script.js +++ b/src/main/webapp/script.js @@ -49,18 +49,19 @@ function newGroupchat() { function loadGroupchat() { const urlParams = new URLSearchParams(window.location.search); const key = urlParams.get('key'); - fetch('/load-groupchat?key=' + key).then(response => response.json()).then((messages) => { - const messageContainer = document.getElementById('messages'); - messageContainer.innerHTML = ''; - for (var i = 0; i < messages.length; i++) { - const message = document.createElement('p'); - message.innerText = messages[i]; - messageContainer.appendChild(message); - } - }).catch(error => - alert('Error: Groupchat does not exist') - ); - + fetch('/load-groupchat?key=' + key).then(response => response.json()) + .catch(error => { + alert('Error: Groupchat does not exist'); + window.location.href = 'index.html'; + }).then((messages) => { + const messageContainer = document.getElementById('messages'); + messageContainer.innerHTML = ''; + for (var i = 0; i < messages.length; i++) { + const message = document.createElement('p'); + message.innerText = messages[i]; + messageContainer.appendChild(message); + } + }); } function redirectToGroupchat(keyParameter) { From 32679636223cedab8b5764c20c8be86fceb3863e Mon Sep 17 00:00:00 2001 From: Tommy Gomez Date: Fri, 17 Jul 2020 00:31:41 +0000 Subject: [PATCH 13/24] begin NewMessageServlet implementation --- .../java/shef/servlets/NewMessageServlet.java | 16 +++++++++++++++- src/main/webapp/groupchat.html | 1 + src/main/webapp/script.js | 4 ++-- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/main/java/shef/servlets/NewMessageServlet.java b/src/main/java/shef/servlets/NewMessageServlet.java index 9c13ed4..b780705 100644 --- a/src/main/java/shef/servlets/NewMessageServlet.java +++ b/src/main/java/shef/servlets/NewMessageServlet.java @@ -43,7 +43,21 @@ public void doGet(HttpServletRequest request, HttpServletResponse response) thro @Override public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException { - + String message = request.getParameter("message"); + if (message.equals("")) { + return; + } + + String keyString = request.getParameter("key"); + Entity groupchatEntity = null; + try { + groupchatEntity = datastore.get(KeyFactory.stringToKey(keyString)); + } catch (EntityNotFoundException e) { + e.printStackTrace(); + return; + } + Object messageObject = groupchatEntity.getProperty("messages"); + ArrayList messages = messageObject != null ? (ArrayList) messageObject : new ArrayList<>(); } } diff --git a/src/main/webapp/groupchat.html b/src/main/webapp/groupchat.html index 0a7f4e7..b4d3b34 100644 --- a/src/main/webapp/groupchat.html +++ b/src/main/webapp/groupchat.html @@ -15,6 +15,7 @@

Groupchat


+
diff --git a/src/main/webapp/script.js b/src/main/webapp/script.js index 5a9f6df..12567db 100644 --- a/src/main/webapp/script.js +++ b/src/main/webapp/script.js @@ -54,8 +54,8 @@ function loadGroupchat() { alert('Error: Groupchat does not exist'); window.location.href = 'index.html'; }).then((messages) => { - const messageContainer = document.getElementById('messages'); - messageContainer.innerHTML = ''; + document.getElementById('messages').innerHTML = ''; + document.getElementById('groupchat-key').value = key; for (var i = 0; i < messages.length; i++) { const message = document.createElement('p'); message.innerText = messages[i]; From fe1b289f3b2a151f862c3ac20fddd1f8ab47fa9f Mon Sep 17 00:00:00 2001 From: Tommy Gomez Date: Fri, 17 Jul 2020 01:33:07 +0000 Subject: [PATCH 14/24] change servlets to use Groupchat class --- .../java/shef/servlets/GroupchatServlet.java | 13 +++---------- .../java/shef/servlets/NewMessageServlet.java | 18 ++++++++---------- src/main/webapp/script.js | 3 ++- 3 files changed, 13 insertions(+), 21 deletions(-) diff --git a/src/main/java/shef/servlets/GroupchatServlet.java b/src/main/java/shef/servlets/GroupchatServlet.java index a60b39d..43ff538 100644 --- a/src/main/java/shef/servlets/GroupchatServlet.java +++ b/src/main/java/shef/servlets/GroupchatServlet.java @@ -27,6 +27,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.ArrayList; +import shef.data.Groupchat; @WebServlet("/load-groupchat") public class GroupchatServlet extends HttpServlet { @@ -41,19 +42,11 @@ public void init() { @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { String keyString = request.getParameter("key"); - Entity groupchatEntity = null; - try { - groupchatEntity = datastore.get(KeyFactory.stringToKey(keyString)); - } catch (EntityNotFoundException e) { - e.printStackTrace(); - return; - } + Groupchat group = new Groupchat(keyString); - Object messageObject = groupchatEntity.getProperty("messages"); - ArrayList messages = messageObject != null ? (ArrayList) messageObject : new ArrayList<>(); response.setContentType("application/json;"); Gson gson = new Gson(); - response.getWriter().println(gson.toJson(messages)); + response.getWriter().println(gson.toJson(group.getMessages())); } @Override diff --git a/src/main/java/shef/servlets/NewMessageServlet.java b/src/main/java/shef/servlets/NewMessageServlet.java index b780705..488908c 100644 --- a/src/main/java/shef/servlets/NewMessageServlet.java +++ b/src/main/java/shef/servlets/NewMessageServlet.java @@ -23,6 +23,8 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import shef.data.MessageUpdate; +import shef.data.MessagePromise; +import shef.data.Groupchat; @WebServlet("/new-message") public class NewMessageServlet extends HttpServlet { @@ -48,16 +50,12 @@ public void doPost(HttpServletRequest request, HttpServletResponse response) thr return; } - String keyString = request.getParameter("key"); - Entity groupchatEntity = null; - try { - groupchatEntity = datastore.get(KeyFactory.stringToKey(keyString)); - } catch (EntityNotFoundException e) { - e.printStackTrace(); - return; - } - Object messageObject = groupchatEntity.getProperty("messages"); - ArrayList messages = messageObject != null ? (ArrayList) messageObject : new ArrayList<>(); + String keyString = request.getParameter("groupchat-key"); + Groupchat group = new Groupchat(keyString); + group.addMessage(message); + group.update(); + + response.setStatus(response.SC_NO_CONTENT); } } diff --git a/src/main/webapp/script.js b/src/main/webapp/script.js index 12567db..0301855 100644 --- a/src/main/webapp/script.js +++ b/src/main/webapp/script.js @@ -54,7 +54,8 @@ function loadGroupchat() { alert('Error: Groupchat does not exist'); window.location.href = 'index.html'; }).then((messages) => { - document.getElementById('messages').innerHTML = ''; + var messageContainer = document.getElementById('messages'); + messageContainer.innerHTML = ''; document.getElementById('groupchat-key').value = key; for (var i = 0; i < messages.length; i++) { const message = document.createElement('p'); From ebf5a53246cba47a38c04fdf4926b934be6d69ce Mon Sep 17 00:00:00 2001 From: Tommy Gomez Date: Fri, 17 Jul 2020 19:42:33 +0000 Subject: [PATCH 15/24] complete doPost --- src/main/java/shef/servlets/NewMessageServlet.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/shef/servlets/NewMessageServlet.java b/src/main/java/shef/servlets/NewMessageServlet.java index 488908c..b0d31df 100644 --- a/src/main/java/shef/servlets/NewMessageServlet.java +++ b/src/main/java/shef/servlets/NewMessageServlet.java @@ -50,11 +50,16 @@ public void doPost(HttpServletRequest request, HttpServletResponse response) thr return; } + // Upload new message to Datastore. String keyString = request.getParameter("groupchat-key"); Groupchat group = new Groupchat(keyString); group.addMessage(message); group.update(); + // Send message to waiting MessagePromises. + messageUpdate.setMessage(message); + messageUpdate.sendMessage(); + response.setStatus(response.SC_NO_CONTENT); } From e8f59faf06f11e0b76c44dc5fc070dc041418cd4 Mon Sep 17 00:00:00 2001 From: Tommy Gomez Date: Fri, 17 Jul 2020 19:57:53 +0000 Subject: [PATCH 16/24] implement doGet --- src/main/java/shef/servlets/NewMessageServlet.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/shef/servlets/NewMessageServlet.java b/src/main/java/shef/servlets/NewMessageServlet.java index b0d31df..cc5e577 100644 --- a/src/main/java/shef/servlets/NewMessageServlet.java +++ b/src/main/java/shef/servlets/NewMessageServlet.java @@ -40,7 +40,13 @@ public void init() { @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { + MessagePromise newMessagePromise = new MessagePromise(); + // Blocks until the next message is received. + String newMessage = newMessagePromise.getNextMessage(); + + response.setContentType("text/html"); + response.getWriter().println(newMessage); } @Override @@ -56,7 +62,7 @@ public void doPost(HttpServletRequest request, HttpServletResponse response) thr group.addMessage(message); group.update(); - // Send message to waiting MessagePromises. + // Send new message to waiting MessagePromises. messageUpdate.setMessage(message); messageUpdate.sendMessage(); From 5b50a0445c39e214080ad210de65de37c4abc7cc Mon Sep 17 00:00:00 2001 From: Tommy Gomez Date: Fri, 17 Jul 2020 20:24:21 +0000 Subject: [PATCH 17/24] add Javadoc --- .../java/shef/servlets/NewMessageServlet.java | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/main/java/shef/servlets/NewMessageServlet.java b/src/main/java/shef/servlets/NewMessageServlet.java index cc5e577..a32c899 100644 --- a/src/main/java/shef/servlets/NewMessageServlet.java +++ b/src/main/java/shef/servlets/NewMessageServlet.java @@ -12,6 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. +/* + * The following source informed the architecture of this servlet and its functional components: + * https://docstore.mik.ua/orelly/java-ent/servlet/ch10_03.htm + */ + package shef.servlets; import com.google.appengine.api.datastore.DatastoreService; @@ -26,6 +31,10 @@ import shef.data.MessagePromise; import shef.data.Groupchat; +/** + * This servlet handles new messages, allowing for clients to see them as they're sent in real time. + * A client sends in new messages with doPost(), and doGet() distributes them to all other active clients. + */ @WebServlet("/new-message") public class NewMessageServlet extends HttpServlet { @@ -38,6 +47,11 @@ public void init() { datastore = DatastoreServiceFactory.getDatastoreService(); } + /** + * Waits for incoming messages using MessagePromises. + * Each GET request instantiates a MessagePromise, which blocks until a new message is received. + * The MessagePromise then unblocks and allows the GET request to respond with the new message. + */ @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { MessagePromise newMessagePromise = new MessagePromise(); @@ -49,6 +63,11 @@ public void doGet(HttpServletRequest request, HttpServletResponse response) thro response.getWriter().println(newMessage); } + /** + * Posts new messages to Datastore and distributes them to active clients using MessageUpdates. + * The message is first added to the groupchat in Datastore, and then distributed to the waiting MessagePromises. + * Empty messages are ignored. + */ @Override public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException { String message = request.getParameter("message"); @@ -68,5 +87,4 @@ public void doPost(HttpServletRequest request, HttpServletResponse response) thr response.setStatus(response.SC_NO_CONTENT); } - } From 84b429dafb05e9af42cb0b1bb31c519057ded0b3 Mon Sep 17 00:00:00 2001 From: Tommy Gomez Date: Mon, 20 Jul 2020 17:54:13 +0000 Subject: [PATCH 18/24] add debugging prints --- src/main/java/shef/data/MessagePromise.java | 5 +++ src/main/java/shef/data/MessageUpdate.java | 8 +++-- .../java/shef/servlets/NewMessageServlet.java | 2 +- src/main/webapp/script.js | 32 ++++++++++++++++--- 4 files changed, 38 insertions(+), 9 deletions(-) diff --git a/src/main/java/shef/data/MessagePromise.java b/src/main/java/shef/data/MessagePromise.java index 7633d61..64497db 100644 --- a/src/main/java/shef/data/MessagePromise.java +++ b/src/main/java/shef/data/MessagePromise.java @@ -29,6 +29,7 @@ public class MessagePromise implements Observer { private MessageUpdate messageUpdate; public MessagePromise(MessageUpdate messageUpdate) { + System.out.println("creating new MessagePromise"); this.message = null; this.updated = false; this.messageUpdate = messageUpdate; @@ -44,7 +45,10 @@ public synchronized String getNextMessage() { // Ensure that the thread waits until an update is detected. while (!updated) { try { + String name = Thread.currentThread().getName(); + System.out.println(name + ": before wait()"); wait(); + System.out.println(name + ":after wait()"); } catch (Exception e) { e.printStackTrace(); } @@ -60,5 +64,6 @@ public synchronized void update(Observable messageUpdate, Object message) { this.message = (String) message; this.updated = true; notify(); + System.out.println("MessagePromise updated"); } } diff --git a/src/main/java/shef/data/MessageUpdate.java b/src/main/java/shef/data/MessageUpdate.java index bf7e42d..5482716 100644 --- a/src/main/java/shef/data/MessageUpdate.java +++ b/src/main/java/shef/data/MessageUpdate.java @@ -31,13 +31,15 @@ public MessageUpdate() { } /** Sends the message to waiting observers via notifyObservers(). */ - public synchronized void sendMessage() { + public void sendMessage() { notifyObservers(message); } /** Set the message and mark the MessageUpdate as changed. */ - public synchronized void setMessage(String message) { - this.message = message; + public void setMessage(String message) { + System.out.println("setting MessageUpdate: " + message); + this.message = message; setChanged(); + System.out.println("Observers: " + countObservers()); } } diff --git a/src/main/java/shef/servlets/NewMessageServlet.java b/src/main/java/shef/servlets/NewMessageServlet.java index a32c899..30aa07b 100644 --- a/src/main/java/shef/servlets/NewMessageServlet.java +++ b/src/main/java/shef/servlets/NewMessageServlet.java @@ -54,7 +54,7 @@ public void init() { */ @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { - MessagePromise newMessagePromise = new MessagePromise(); + MessagePromise newMessagePromise = new MessagePromise(messageUpdate); // Blocks until the next message is received. String newMessage = newMessagePromise.getNextMessage(); diff --git a/src/main/webapp/script.js b/src/main/webapp/script.js index 0301855..2884c15 100644 --- a/src/main/webapp/script.js +++ b/src/main/webapp/script.js @@ -54,18 +54,40 @@ function loadGroupchat() { alert('Error: Groupchat does not exist'); window.location.href = 'index.html'; }).then((messages) => { - var messageContainer = document.getElementById('messages'); - messageContainer.innerHTML = ''; + document.getElementById('messages').innerHTML = ''; document.getElementById('groupchat-key').value = key; for (var i = 0; i < messages.length; i++) { - const message = document.createElement('p'); - message.innerText = messages[i]; - messageContainer.appendChild(message); + addMessage(messages[i]); } + setTimeout(getNextMessage(), 100); }); } +function getNextMessage() { + console.log('getting a new message'); + const request = new Request("/new-message", {method: 'GET'}) + console.log("Request: " + request); + fetch(request) + .then(response => { + console.log("In response => response.text() block") + return response.text() + }, err => alert('servlet error ' + err)) + .then(message => { + console.log('got message ' + message); + addMessage(message); + getNextMessage(); + }, err => alert('text() error ' + err)); + console.log("outside of fetch block"); +} + function redirectToGroupchat(keyParameter) { const key = keyParameter ? keyParameter : document.getElementById('groupchat-key').value; window.location.href = "/groupchat.html?key=" + key; } + +function addMessage(message) { + var messagesContainer = document.getElementById('messages'); + const messageElement = document.createElement('p'); + messageElement.innerText = message; + messagesContainer.appendChild(messageElement); +} From fbb5764bd6ed4578ebd6d5c9afd67f1f0a7b89f0 Mon Sep 17 00:00:00 2001 From: Tommy Gomez Date: Tue, 21 Jul 2020 22:26:26 +0000 Subject: [PATCH 19/24] change HTML form to call JS function to submit messages --- src/main/webapp/groupchat.html | 10 +++++----- src/main/webapp/script.js | 30 ++++++++++++++++++++---------- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/src/main/webapp/groupchat.html b/src/main/webapp/groupchat.html index b4d3b34..aa6d93a 100644 --- a/src/main/webapp/groupchat.html +++ b/src/main/webapp/groupchat.html @@ -5,18 +5,18 @@ shef - + - +

Groupchat

-
+
- - + +
\ No newline at end of file diff --git a/src/main/webapp/script.js b/src/main/webapp/script.js index 2884c15..2464c6b 100644 --- a/src/main/webapp/script.js +++ b/src/main/webapp/script.js @@ -40,7 +40,7 @@ function addParagraph(content) { } function newGroupchat() { - const request = new Request("/load-groupchat", {method: 'POST'}); + var request = new Request("/load-groupchat", {method: 'POST'}); fetch(request).then(response => response.text()).then((key) => { redirectToGroupchat(key); }); @@ -49,9 +49,9 @@ function newGroupchat() { function loadGroupchat() { const urlParams = new URLSearchParams(window.location.search); const key = urlParams.get('key'); - fetch('/load-groupchat?key=' + key).then(response => response.json()) - .catch(error => { - alert('Error: Groupchat does not exist'); + fetch('/load-groupchat?key=' + key) + .then(response => response.json(), error => { + alert('Error: Groupchat does not exist ' + error); window.location.href = 'index.html'; }).then((messages) => { document.getElementById('messages').innerHTML = ''; @@ -59,25 +59,35 @@ function loadGroupchat() { for (var i = 0; i < messages.length; i++) { addMessage(messages[i]); } - setTimeout(getNextMessage(), 100); + getNextMessage(); }); } +function postNextMessage() { + const message = document.getElementById('message-input').value; + const groupKey = document.getElementById('groupchat-key').value; + var request = new Request('/new-message?message=' + message + '&groupchat-key=' + groupKey, {method: 'POST'}); + fetch(request) + .then(v => console.log('POST success'), v => console.log('POST failure')); +} + function getNextMessage() { console.log('getting a new message'); - const request = new Request("/new-message", {method: 'GET'}) + var request = new Request("/new-message", {method: 'GET'}) console.log("Request: " + request); fetch(request) .then(response => { - console.log("In response => response.text() block") - return response.text() - }, err => alert('servlet error ' + err)) + console.log("In response => response.text() block"); + return response.text(); + }, error => { + console.log('SERVER ERROR: ' + error); + //getNextMessage(); + }) .then(message => { console.log('got message ' + message); addMessage(message); getNextMessage(); }, err => alert('text() error ' + err)); - console.log("outside of fetch block"); } function redirectToGroupchat(keyParameter) { From 480f6139f5506f1d78ba940192e56d3cfa47bed9 Mon Sep 17 00:00:00 2001 From: Tommy Gomez Date: Tue, 21 Jul 2020 22:26:52 +0000 Subject: [PATCH 20/24] override service() to handle botched requests --- .../java/shef/servlets/NewMessageServlet.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/main/java/shef/servlets/NewMessageServlet.java b/src/main/java/shef/servlets/NewMessageServlet.java index 30aa07b..75c668b 100644 --- a/src/main/java/shef/servlets/NewMessageServlet.java +++ b/src/main/java/shef/servlets/NewMessageServlet.java @@ -54,6 +54,7 @@ public void init() { */ @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { + System.out.println(Thread.currentThread().getName() + ": GET request made for next mesasge"); MessagePromise newMessagePromise = new MessagePromise(messageUpdate); // Blocks until the next message is received. @@ -87,4 +88,22 @@ public void doPost(HttpServletRequest request, HttpServletResponse response) thr response.setStatus(response.SC_NO_CONTENT); } + + @Override + public void service(HttpServletRequest request, HttpServletResponse response) throws IOException { + System.out.println("NEW REQUEST: " + request.getMethod() + " " + request.getRequestURL()); + if (request.getMethod().equals("ET")) { + System.out.println("FOUND ET"); + doGet(request, response); + } else if (request.getMethod().equals("OST")) { + System.out.println("FOUND OST"); + response.sendError(response.SC_BAD_REQUEST); + } else { + try { + super.service(request, response); + } catch (Exception e) { + e.printStackTrace(); + } + } + } } From 893664747f59e575d33d18672096e974412f56f6 Mon Sep 17 00:00:00 2001 From: Tommy Gomez Date: Tue, 21 Jul 2020 22:27:17 +0000 Subject: [PATCH 21/24] print statements --- src/main/java/shef/data/MessagePromise.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/shef/data/MessagePromise.java b/src/main/java/shef/data/MessagePromise.java index 64497db..0f0eddf 100644 --- a/src/main/java/shef/data/MessagePromise.java +++ b/src/main/java/shef/data/MessagePromise.java @@ -29,11 +29,10 @@ public class MessagePromise implements Observer { private MessageUpdate messageUpdate; public MessagePromise(MessageUpdate messageUpdate) { - System.out.println("creating new MessagePromise"); + System.out.println(Thread.currentThread().getName() + ": creating new MessagePromise"); this.message = null; this.updated = false; this.messageUpdate = messageUpdate; - this.messageUpdate.addObserver(this); } /** @@ -42,6 +41,8 @@ public MessagePromise(MessageUpdate messageUpdate) { * It then unblocks, and returns the message to the servlet. */ public synchronized String getNextMessage() { + messageUpdate.addObserver(this); + // Ensure that the thread waits until an update is detected. while (!updated) { try { @@ -64,6 +65,6 @@ public synchronized void update(Observable messageUpdate, Object message) { this.message = (String) message; this.updated = true; notify(); - System.out.println("MessagePromise updated"); + System.out.println(Thread.currentThread().getName() + ": MessagePromise updated"); } } From c6cd8662dbb379ac061d100a4b05d6ef44b75ae0 Mon Sep 17 00:00:00 2001 From: Tommy Gomez Date: Wed, 22 Jul 2020 00:17:47 +0000 Subject: [PATCH 22/24] remove prints --- src/main/webapp/script.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/webapp/script.js b/src/main/webapp/script.js index 2464c6b..fa1cb3e 100644 --- a/src/main/webapp/script.js +++ b/src/main/webapp/script.js @@ -74,7 +74,6 @@ function postNextMessage() { function getNextMessage() { console.log('getting a new message'); var request = new Request("/new-message", {method: 'GET'}) - console.log("Request: " + request); fetch(request) .then(response => { console.log("In response => response.text() block"); @@ -84,7 +83,7 @@ function getNextMessage() { //getNextMessage(); }) .then(message => { - console.log('got message ' + message); + console.log('got message "' + message + '"'); addMessage(message); getNextMessage(); }, err => alert('text() error ' + err)); From 4f99ab9daa58463d0d2b8a95b662766eae9e7833 Mon Sep 17 00:00:00 2001 From: Tommy Gomez Date: Thu, 23 Jul 2020 01:28:05 +0000 Subject: [PATCH 23/24] rebase out, saving prints --- src/main/java/shef/data/MessagePromise.java | 7 +++--- .../java/shef/servlets/NewMessageServlet.java | 13 ++++++++--- src/main/webapp/script.js | 23 ++++++++++++------- 3 files changed, 29 insertions(+), 14 deletions(-) diff --git a/src/main/java/shef/data/MessagePromise.java b/src/main/java/shef/data/MessagePromise.java index 0f0eddf..0421367 100644 --- a/src/main/java/shef/data/MessagePromise.java +++ b/src/main/java/shef/data/MessagePromise.java @@ -29,7 +29,7 @@ public class MessagePromise implements Observer { private MessageUpdate messageUpdate; public MessagePromise(MessageUpdate messageUpdate) { - System.out.println(Thread.currentThread().getName() + ": creating new MessagePromise"); + //System.out.println(Thread.currentThread().getName() + ": creating new MessagePromise"); this.message = null; this.updated = false; this.messageUpdate = messageUpdate; @@ -47,15 +47,16 @@ public synchronized String getNextMessage() { while (!updated) { try { String name = Thread.currentThread().getName(); - System.out.println(name + ": before wait()"); + //System.out.println(name + ": before wait()"); wait(); - System.out.println(name + ":after wait()"); + //System.out.println(name + ":after wait()"); } catch (Exception e) { e.printStackTrace(); } } messageUpdate.deleteObserver(this); + this.updated = false; return message; } diff --git a/src/main/java/shef/servlets/NewMessageServlet.java b/src/main/java/shef/servlets/NewMessageServlet.java index 75c668b..9233b05 100644 --- a/src/main/java/shef/servlets/NewMessageServlet.java +++ b/src/main/java/shef/servlets/NewMessageServlet.java @@ -31,6 +31,9 @@ import shef.data.MessagePromise; import shef.data.Groupchat; +import java.util.*; +import java.text.SimpleDateFormat; + /** * This servlet handles new messages, allowing for clients to see them as they're sent in real time. * A client sends in new messages with doPost(), and doGet() distributes them to all other active clients. @@ -40,11 +43,14 @@ public class NewMessageServlet extends HttpServlet { private MessageUpdate messageUpdate; private DatastoreService datastore; + private SimpleDateFormat df; @Override public void init() { messageUpdate = new MessageUpdate(); datastore = DatastoreServiceFactory.getDatastoreService(); + df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); + df.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles")); } /** @@ -54,7 +60,7 @@ public void init() { */ @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { - System.out.println(Thread.currentThread().getName() + ": GET request made for next mesasge"); + System.out.println(Thread.currentThread().getName() + ": GET request made for next message"); MessagePromise newMessagePromise = new MessagePromise(messageUpdate); // Blocks until the next message is received. @@ -89,9 +95,10 @@ public void doPost(HttpServletRequest request, HttpServletResponse response) thr response.setStatus(response.SC_NO_CONTENT); } - @Override + @Override public void service(HttpServletRequest request, HttpServletResponse response) throws IOException { - System.out.println("NEW REQUEST: " + request.getMethod() + " " + request.getRequestURL()); + String time = df.format(new Date(System.currentTimeMillis())); + System.out.println(time + " NEW REQUEST: " + request.getMethod() + " " + request.getRequestURL()); if (request.getMethod().equals("ET")) { System.out.println("FOUND ET"); doGet(request, response); diff --git a/src/main/webapp/script.js b/src/main/webapp/script.js index fa1cb3e..9e65545 100644 --- a/src/main/webapp/script.js +++ b/src/main/webapp/script.js @@ -68,25 +68,32 @@ function postNextMessage() { const groupKey = document.getElementById('groupchat-key').value; var request = new Request('/new-message?message=' + message + '&groupchat-key=' + groupKey, {method: 'POST'}); fetch(request) - .then(v => console.log('POST success'), v => console.log('POST failure')); + .then(() => { + console.log('POST success'); + document.getElementById('message-input').value = ''; + }, () => console.log('POST failure')); } function getNextMessage() { console.log('getting a new message'); var request = new Request("/new-message", {method: 'GET'}) + console.log('sending request ' + request.url + ' ' + request.method); fetch(request) .then(response => { - console.log("In response => response.text() block"); - return response.text(); - }, error => { - console.log('SERVER ERROR: ' + error); - //getNextMessage(); + if (response.ok) { + console.log("Received response " + response); + return response.text(); + } else { + throw new Error('Servlet closed'); + } }) .then(message => { - console.log('got message "' + message + '"'); + console.log('Got message "' + message + '"'); addMessage(message); + console.log('recursively calling getNextMessage()') getNextMessage(); - }, err => alert('text() error ' + err)); + }) + .catch(err => console.log(err)); } function redirectToGroupchat(keyParameter) { From 18d595ec6ef16fff94131feafd9a499bbf589506 Mon Sep 17 00:00:00 2001 From: Tommy Gomez Date: Fri, 31 Jul 2020 18:37:14 +0000 Subject: [PATCH 24/24] clean print statements --- src/main/java/shef/data/MessagePromise.java | 5 --- src/main/java/shef/data/MessageUpdate.java | 2 -- .../java/shef/servlets/NewMessageServlet.java | 26 ---------------- src/main/webapp/script.js | 31 +++++++++++-------- 4 files changed, 18 insertions(+), 46 deletions(-) diff --git a/src/main/java/shef/data/MessagePromise.java b/src/main/java/shef/data/MessagePromise.java index 0421367..7588592 100644 --- a/src/main/java/shef/data/MessagePromise.java +++ b/src/main/java/shef/data/MessagePromise.java @@ -29,7 +29,6 @@ public class MessagePromise implements Observer { private MessageUpdate messageUpdate; public MessagePromise(MessageUpdate messageUpdate) { - //System.out.println(Thread.currentThread().getName() + ": creating new MessagePromise"); this.message = null; this.updated = false; this.messageUpdate = messageUpdate; @@ -46,10 +45,7 @@ public synchronized String getNextMessage() { // Ensure that the thread waits until an update is detected. while (!updated) { try { - String name = Thread.currentThread().getName(); - //System.out.println(name + ": before wait()"); wait(); - //System.out.println(name + ":after wait()"); } catch (Exception e) { e.printStackTrace(); } @@ -66,6 +62,5 @@ public synchronized void update(Observable messageUpdate, Object message) { this.message = (String) message; this.updated = true; notify(); - System.out.println(Thread.currentThread().getName() + ": MessagePromise updated"); } } diff --git a/src/main/java/shef/data/MessageUpdate.java b/src/main/java/shef/data/MessageUpdate.java index 5482716..3651a28 100644 --- a/src/main/java/shef/data/MessageUpdate.java +++ b/src/main/java/shef/data/MessageUpdate.java @@ -37,9 +37,7 @@ public void sendMessage() { /** Set the message and mark the MessageUpdate as changed. */ public void setMessage(String message) { - System.out.println("setting MessageUpdate: " + message); this.message = message; setChanged(); - System.out.println("Observers: " + countObservers()); } } diff --git a/src/main/java/shef/servlets/NewMessageServlet.java b/src/main/java/shef/servlets/NewMessageServlet.java index 9233b05..30aa07b 100644 --- a/src/main/java/shef/servlets/NewMessageServlet.java +++ b/src/main/java/shef/servlets/NewMessageServlet.java @@ -31,9 +31,6 @@ import shef.data.MessagePromise; import shef.data.Groupchat; -import java.util.*; -import java.text.SimpleDateFormat; - /** * This servlet handles new messages, allowing for clients to see them as they're sent in real time. * A client sends in new messages with doPost(), and doGet() distributes them to all other active clients. @@ -43,14 +40,11 @@ public class NewMessageServlet extends HttpServlet { private MessageUpdate messageUpdate; private DatastoreService datastore; - private SimpleDateFormat df; @Override public void init() { messageUpdate = new MessageUpdate(); datastore = DatastoreServiceFactory.getDatastoreService(); - df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); - df.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles")); } /** @@ -60,7 +54,6 @@ public void init() { */ @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { - System.out.println(Thread.currentThread().getName() + ": GET request made for next message"); MessagePromise newMessagePromise = new MessagePromise(messageUpdate); // Blocks until the next message is received. @@ -94,23 +87,4 @@ public void doPost(HttpServletRequest request, HttpServletResponse response) thr response.setStatus(response.SC_NO_CONTENT); } - - @Override - public void service(HttpServletRequest request, HttpServletResponse response) throws IOException { - String time = df.format(new Date(System.currentTimeMillis())); - System.out.println(time + " NEW REQUEST: " + request.getMethod() + " " + request.getRequestURL()); - if (request.getMethod().equals("ET")) { - System.out.println("FOUND ET"); - doGet(request, response); - } else if (request.getMethod().equals("OST")) { - System.out.println("FOUND OST"); - response.sendError(response.SC_BAD_REQUEST); - } else { - try { - super.service(request, response); - } catch (Exception e) { - e.printStackTrace(); - } - } - } } diff --git a/src/main/webapp/script.js b/src/main/webapp/script.js index 9e65545..412da7c 100644 --- a/src/main/webapp/script.js +++ b/src/main/webapp/script.js @@ -39,6 +39,7 @@ function addParagraph(content) { return "

" + content + "

"; } +/** Creates a new groupchat and redirects the client to the chatting page. */ function newGroupchat() { var request = new Request("/load-groupchat", {method: 'POST'}); fetch(request).then(response => response.text()).then((key) => { @@ -46,6 +47,7 @@ function newGroupchat() { }); } +/** Loads an existing groupchat. */ function loadGroupchat() { const urlParams = new URLSearchParams(window.location.search); const key = urlParams.get('key'); @@ -63,44 +65,47 @@ function loadGroupchat() { }); } +/** Posts a message to a groupchat. */ function postNextMessage() { const message = document.getElementById('message-input').value; const groupKey = document.getElementById('groupchat-key').value; var request = new Request('/new-message?message=' + message + '&groupchat-key=' + groupKey, {method: 'POST'}); - fetch(request) - .then(() => { - console.log('POST success'); - document.getElementById('message-input').value = ''; - }, () => console.log('POST failure')); + fetch(request).then( + document.getElementById('message-input').value = '' + ); } +/** + * Sends a request to the server to get the next message. + * This method is recursive (upon success) so that each client is always waiting for the next message. + * Requests use asynchronous Promises, so the client can perform other functions while waiting for a message. + */ function getNextMessage() { - console.log('getting a new message'); var request = new Request("/new-message", {method: 'GET'}) - console.log('sending request ' + request.url + ' ' + request.method); fetch(request) .then(response => { if (response.ok) { - console.log("Received response " + response); return response.text(); } else { throw new Error('Servlet closed'); } - }) - .then(message => { - console.log('Got message "' + message + '"'); + }).then(message => { addMessage(message); - console.log('recursively calling getNextMessage()') getNextMessage(); }) - .catch(err => console.log(err)); + .catch(err => { + alert(err); + window.location.href = 'index.html'; + }); } +/** Given a groupchat key, redirects the client to that groupchat. */ function redirectToGroupchat(keyParameter) { const key = keyParameter ? keyParameter : document.getElementById('groupchat-key').value; window.location.href = "/groupchat.html?key=" + key; } +/** Adds a

element containing a message to a groupchat. */ function addMessage(message) { var messagesContainer = document.getElementById('messages'); const messageElement = document.createElement('p');