I am new to Java Servlet concepts and Web Development with Java.
I am trying to implement a notification System using ServerSentEvents.
I know that whenever an announcement was made, It will be stored in the database and then need to notify the logged in users.
If an user not have an active session whenever he logged in he will pull the messages which are not delivered to him from the database.
For this case I tried to connect with EventSource for a Servlet and there I need to hold the connection to sent stream of events to particular users if they received any information for them.To hold the connection I used wait using an object.
But using wait and Sleep is not recommended.I need to know to hold the connection long lived until user closes that page.
Here is the following implementation I have done so far.
@WebServlet("/notification")public class NotificationSSE extends HttpServlet { @Override public void init() throws ServletException { this.getServletContext().setAttribute("is_message", new Object()); super.init(); } @Override protected void doGet(HttpServletRequest reuest, HttpServletResponse response) throws ServletException, IOException { Object obj = null; try { obj = this.getServletContext().getAttribute("is_message"); response.setContentType("text/event-stream"); response.setCharacterEncoding("UTF-8"); PrintWriter writer = response.getWriter(); MessagesHolder.users.add(response); synchronized (obj) { obj.wait(); } } catch (Exception e) { e.printStackTrace(); } }}
This is the MessageHolder which will be responsible to send message
I have a plan to change the Vector to a HashMap which would link the user and send the Message only to the particular user
public class MessagesHolder { public static Vector<HttpServletResponse> users = new Vector<>(); public void sendMessage(Message message) { try { for (HttpServletResponse user : users) { PrintWriter writer = user.getWriter(); writer.write("data: " + message.toJson() +"\n\n"); writer.flush(); } } catch (Exception e) { e.printStackTrace(); } }}
This is a servlet which is responsible for receiving the messages post by the user and stores it in the database
@WebServlet("/send-message")public class SendMessage extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { try { String messageSubject = req.getParameter("message_subject"); String messageContent = req.getParameter("message_content"); String messageSendTime = req.getParameter("message_sendTime"); String[] receivers = req.getParameterValues("receivers[]"); String user_id = req.getSession().getAttribute("user_id").toString(); try ( Connection conn = DriverManager.getConnection(DBUtil.getUrl(), DBUtil.getUser(), DBUtil.getPassword()); PreparedStatement insertMessage = conn.prepareStatement("INSERT INTO Message(message_title, message_content, sender_id, send_time) VALUES (?, ?, ?, ?)", Statement.RETURN_GENERATED_KEYS); PreparedStatement insertNotify = conn .prepareStatement("INSERT INTO Notification (message_id, receiver_id) VALUES (?,?)"); PrintWriter out = resp.getWriter();) { insertMessage.setString(1, messageSubject); insertMessage.setString(2, messageContent); insertMessage.setString(3, user_id); insertMessage.setString(4, messageSendTime.split("T")[0] +" " + messageSendTime.split("T")[1] +":00"); insertMessage.executeUpdate(); Message message = new Message(user_id, messageSubject, messageContent); ResultSet generatedKeys = insertMessage.getGeneratedKeys(); if (generatedKeys.next()) { int i = 0; Vector<String> receiverList = new Vector<>(); long messageId = generatedKeys.getLong(1); insertNotify.setLong(1, messageId); while (i < receivers.length) { insertNotify.setString(2, receivers[i]); insertNotify.addBatch(); receiverList.add(receivers[i]); i++; } insertNotify.executeBatch(); out.write("sent succssfully"); MessagesHolder messagesHolder = new MessagesHolder(); messagesHolder.sendMessage(message); out.flush(); } } catch (Exception ex) { ex.printStackTrace(); } } catch (Exception e) { e.printStackTrace(); } }}
The Message Object
public class Message { public String senderId; public String title; public String message; public Status status; public Message(String senderId, String title, String message) { this.senderId = senderId; this.title = title; this.message = message; this.status = Status.SENT; } @Override public String toString() { return "Message [senderId=" + senderId +", title=" + title +", message=" + message +", status=" + status+"]"; } public JSONObject toJson(){ JSONObject obj = new JSONObject(); obj.put("senderId", senderId); obj.put("title", title); obj.put("message", message); obj.put("status", status); return obj; }}
Client side JS
let eventSource = new EventSource("notification");const list = document.querySelector("ul");eventSource.onopen = (event) => { list.append("Connection created"); };eventSource.onerror = (event) => { console.log("Error occured"); console.log(event);};eventSource.onmessage = function (event) { let listItem = document.createElement("li"); listItem.innerText = event.data; list.append(listItem); console.log(event, event.data);};
I am expecting what are the best ways to hold the connection of the user in order to send the messages based on the receiver-list I am getting from the Post request which holds the user-Ids of the user.