I am trying to implement real-time notification system using Servlet and ServerSentEvents
This is the following code I have implemented
@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() + "nn");
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;
}
}
Is there any better way to implement this because I read that It’s not recommended to use wait() inside request
-
What are other ways I could implement the server sent events to achieve the notification sending.
-
I don’t know much about Http2 keep-alive connection, Is there any possibility with that I can create a channel send the event streams with that
-
Also need a clarification that is there a possibility that could I implement this with ServletListeners by any chance and send the notification