title: Server-sent events (SSE) with Jetty (programatic setup)
body: <p>I have problems setting up a SSE environment with Jetty. I use Chrome (44.0.2403.107 m) and FF (39.0) as client browsers.</p>
  
  <p>I created a servlet in Jetty (see below) and used a WebAppContext to make it available programatically. I also tried to use the <code>EventSourceServlet</code> provided by Jetty, however, this didn't work either.</p>
  
  <p>On the client side I created a simple <code>EventSource</code> and tried to get the messages. While <code>curl</code> delivers the correct output (see output below), FF and Chrome do not fire the event as expected. After killing the server, the events seem to pop up in the browsers (after the timeout of the request).</p>
  
  <p>Can anyone point out my error while implementing SSE with Jetty?</p>
  
  <p>I also recognized that jetty uses special <code>write</code> methods with respect to async writing. However, in the <code>EventSourceServlet</code> these methods are not used. Do I have to use those for SSE to work? Also, at which points in my servlet can I omit the <code>flush</code>?</p>
  
  <p>The servlet I created:</p>
  
  <pre><code>package de.rub.lps.sophie.agenten.sample.webui.servlet;
  
  import java.io.IOException;
  import java.nio.charset.StandardCharsets;
  
  import javax.servlet.ServletException;
  import javax.servlet.ServletOutputStream;
  import javax.servlet.http.HttpServlet;
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpServletResponse;
  
  import org.eclipse.jetty.server.AsyncContextState;
  
  public class TestServlet extends HttpServlet {
  
      private static final long serialVersionUID = -8049945594360149181L;
  
      @Override
      protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  
          System.out.println(req.getSession(true).getId());
  
          resp.setStatus(HttpServletResponse.SC_OK);
          resp.setContentType("text/event-stream");
          resp.setCharacterEncoding(StandardCharsets.UTF_8.name());
          resp.flushBuffer();
          AsyncContextState async = (AsyncContextState) req.startAsync();
  
          System.out.println(async);
  
          new Thread() {
              public void run() {
                  try {
                      for (int i = 0; i &lt; 3; i++) {
                          try {
                              Thread.sleep(3000);
                          } catch (InterruptedException e) {
                              e.printStackTrace();
                          }
                          ServletOutputStream outputStream = async.getResponse().getOutputStream();
                          if (outputStream.isReady()) {
                              String message = "data: refresh\n\n";
                              outputStream.write(message.getBytes(StandardCharsets.UTF_8), 0, message.length());
                              outputStream.flush();
                              async.getResponse().flushBuffer();
                          } else {
                              System.out.println("not ready!");
                          }
                          System.out.println("wrote!");
                      }
                  } catch (IOException e) {
                      async.complete();
                      e.printStackTrace();
                  }
              };
          }.start();
      }
  
  }
  </code></pre>
  
  <p>An excerpt of how I start the Jetty and add the WebAppContext with the servlet (included in a big try/catch...):</p>
  
  <pre><code>HandlerCollection handlerCollection = new HandlerCollection(true);
  server = new Server(8888);
  server.setHandler(handlerCollection);
  server.start();
  
  WebAppContext context = new WebAppContext();
  handlerCollection.addHandler(context);
  context.setContextPath("/test");
  context.setResourceBase("/myPath");
  ServletHolder servletHolder = new ServletHolder(new TestServlet());
  servletHolder.setAsyncSupported(true);
  context.addServlet(servletHolder, "/test");
  context.start()
  </code></pre>
  
  <p>The output by <code>curl</code>:</p>
  
  <pre><code>&gt; GET /Agentname@134.147.100.87:1099/JADE/test HTTP/1.1
  &gt; Host: 127.0.0.1:8888
  &gt; User-Agent: curl/7.43.0
  &gt; Accept: */*
  &gt;
  &lt; HTTP/1.1 200 OK
  &lt; Date: Wed, 29 Jul 2015 09:08:05 GMT
  &lt; Set-Cookie: JSESSIONID=aw6ro34htalm1uf5huix9bxo6;Path=/test/test
  &lt; Expires: Thu, 01 Jan 1970 00:00:00 GMT
  &lt; Content-Type: text/event-stream;charset=utf-8
  &lt; Transfer-Encoding: chunked
  &lt; Server: Jetty(9.3.1.v20150714)
  &lt;
  
  data: refresh
  
  data: refresh
  
  data: refresh
  
  [... and so on...]
  </code></pre>
  
  <p>And the <code>test.html</code> I use in the browsers:</p>
  
  <pre><code>&lt;!DOCTYPE html&gt;
  &lt;html&gt;
  &lt;head&gt;
  &lt;meta charset="ISO-8859-1"&gt;
  &lt;title&gt;Insert title here&lt;/title&gt;
  &lt;/head&gt;
  &lt;body&gt;
  &lt;script&gt;
   var eventSource = new EventSource('test');
   eventSource.onmessage = function(event) {
       console.log(event);
       window.alert(event.data);
   };
  &lt;/script&gt;
  
  &lt;/body&gt;
  &lt;/html&gt;
  </code></pre>