Skip to content

Instantly share code, notes, and snippets.

@junlapong
Forked from chRyNaN/DefaultListener.java
Created January 28, 2022 10:32
Show Gist options
  • Select an option

  • Save junlapong/59a66464f62bb48c2cc3b9f5c60334f3 to your computer and use it in GitHub Desktop.

Select an option

Save junlapong/59a66464f62bb48c2cc3b9f5c60334f3 to your computer and use it in GitHub Desktop.

Revisions

  1. @chRyNaN chRyNaN revised this gist Jan 20, 2015. 4 changed files with 0 additions and 0 deletions.
    File renamed without changes.
    File renamed without changes.
    File renamed without changes.
    File renamed without changes.
  2. @chRyNaN chRyNaN created this gist Jan 20, 2015.
    3 changes: 3 additions & 0 deletions DefaultListener
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,3 @@
    public interface DefaultListener {
    public void onNotification(NotificationEvent event);
    }
    80 changes: 80 additions & 0 deletions NotificationChannel
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,80 @@
    import java.io.IOException;
    import java.io.PrintWriter;
    import java.util.concurrent.ConcurrentHashMap;
    import java.util.concurrent.ConcurrentMap;

    import javax.inject.Inject;
    import javax.servlet.AsyncContext;
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;

    @WebServlet(urlPatterns = {"/notify"}, asyncSupported = true)
    public class NotificationChannel extends HttpServlet implements DefaultListener{
    private static final long serialVersionUID = -2827663265593547983L;
    private ConcurrentMap<String, AsyncContext> contexts = new ConcurrentHashMap<>();
    @Inject
    NotificationListener listener;

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
    //initialize for server-sent events
    response.setContentType("text/event-stream");
    response.setCharacterEncoding("UTF-8");

    final String userId = request.getParameter("userId"); //retrieve the user Id
    if (userId == null){
    response.sendError(HttpServletResponse.SC_BAD_REQUEST);
    return;
    }

    //to clear threads and allow for asynchronous execution
    final AsyncContext asyncContext = request.startAsync(request, response);
    asyncContext.setTimeout(0);

    //add context to list for later use
    if (contexts == null || contexts.isEmpty() || !contexts.containsKey(userId)){
    if (contexts == null){
    contexts = new ConcurrentHashMap<String, AsyncContext>();
    }
    contexts.put(userId, asyncContext);
    }

    listener.addListener(this);
    sendNotification(userId, "connected");
    }

    protected void sendNotification(String userId, String notification){
    try{
    if(contexts.containsKey(userId)){
    AsyncContext asyncContext = contexts.get(userId);
    PrintWriter writer = asyncContext.getResponse().getWriter();
    writer.write("data: " + notification + "\n\n");
    writer.flush();
    }
    }catch (Exception e){
    e.printStackTrace();
    //try again before disconnecting the user
    try{
    if(contexts.containsKey(userId)){
    AsyncContext asyncContext = contexts.get(userId);
    PrintWriter writer = asyncContext.getResponse().getWriter();
    writer.write("data: " + notification + "\n\n");
    writer.flush();
    }
    }catch (Exception e2){
    e2.printStackTrace();
    AsyncContext asyncContext = contexts.remove(userId);
    asyncContext.complete();
    }
    }
    }

    @Override
    public void onNotification(NotificationEvent event) {
    this.sendNotification(event.getUserId(), event.getJSONEvent());
    }

    }
    44 changes: 44 additions & 0 deletions NotificationEvent
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,44 @@
    import org.json.JSONException;
    import org.json.JSONObject;

    public class NotificationEvent {
    private String type;
    private String message;
    private String toUserId;

    public NotificationEvent(String type, String message, String toUserId){
    this.type = type;
    this.message = message;
    this.toUserId = toUserId;
    }

    public NotificationEvent(String type, String toUserId){
    this.type = type;
    this.message = "";
    this.toUserId = toUserId;
    }

    public String getType(){
    return this.type;
    }

    public String getMessage(){
    return this.message;
    }

    public String getUserId(){
    return this.toUserId;
    }

    public String getJSONEvent(){
    JSONObject obj = new JSONObject();
    try {
    obj.put("type", type);
    obj.put("message", message);
    } catch (JSONException e) {
    e.printStackTrace();
    }
    return obj.toString();
    }

    }
    33 changes: 33 additions & 0 deletions NotificationListener
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,33 @@
    import java.util.ArrayList;
    import java.util.List;

    import javax.ejb.Asynchronous;
    import javax.ejb.Stateful;
    import javax.enterprise.context.ApplicationScoped;
    import javax.enterprise.event.Observes;

    @Stateful
    @ApplicationScoped
    public class NotificationListener {

    List<DefaultListener> listeners = new ArrayList<>();

    public void addListener(DefaultListener l){
    listeners.add(l);
    }

    @Asynchronous
    public void listenForNotifications(@Observes NotificationEvent event){
    //this method is called by the container whenever a NotificationEvent is fired
    for (DefaultListener l : listeners){
    l.onNotification(event);
    }
    }

    @Asynchronous
    public void checkForUpdates(String userId){
    //manually check the database for updates

    }

    }
    14 changes: 14 additions & 0 deletions notify.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,14 @@
    (function(){
    console.log("notify.js");
    var eventSource = new EventSource("notify?userId=123456");//need a way to access userId from server, then apply it here
    eventSource.onopen = function(e){
    console.log("Connection Opened");
    };
    eventSource.onmessage = function(e){
    console.log("Message: " + e.data);
    };
    eventSource.onerror = function(e){
    console.log("Error");
    };

    })();