0

I read multiple questions that are similar to mine and found this: https://stackoverflow.com/a/34358215/12550134

But I am not able to do this. I use plain JAX-RS API and Open Liberty as my server. Unfortunately the ResourceConfig cannot be found, so I cannot disable the buffer, as described in the answer above.

This is my code:

@GET
@Produces(MediaType.TEXT_PLAIN)
public Response sayHelloStream() {
    LOGGER.debug("calling sayHelloStream");
    StreamingOutput out = outputStream -> {
        Writer writer = new BufferedWriter(new OutputStreamWriter(outputStream));
        for (int i = 0; i < 999999999; i++) {
            writer.write("Hello\n");
            writer.flush();

            try {
                LOGGER.debug("before sleep");
                TimeUnit.SECONDS.sleep(3);
                LOGGER.debug("after sleep");
            } catch (InterruptedException e) {
                LOGGER.error("error with the timer", e);
            }
        }
    };
    return Response.ok(out).build();
}

When calling it in the browser nothing happens. To my understanding due to the buffer. How am I able to stream text data like this using plain JAX-RS?

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
Apollo
  • 1,296
  • 2
  • 11
  • 24

1 Answers1

3

I would use the SSE extension. AFAIK it's part of the JAX-RS API, allthough you might need an extra module to enable it server-side:

https://eclipse-ee4j.github.io/jersey.github.io/documentation/latest/sse.html

...
import javax.ws.rs.sse.Sse;
import javax.ws.rs.sse.SseEventSink;
import javax.ws.rs.sse.OutboundSseEvent;
...
 
@Path("events")
public static class SseResource {
 
    @GET
    @Produces(MediaType.SERVER_SENT_EVENTS)
    public void getServerSentEvents(@Context SseEventSink eventSink, @Context Sse sse) {
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                // ... code that waits 1 second
                final OutboundSseEvent event = sse.newEventBuilder()
                    .name("message-to-client")
                    .data(String.class, "Hello world " + i + "!")
                    .build();
                eventSink.send(event);
            }
        }).start();
    }
}

It streams text data to the client in chunks in the SSE format, so it can easily be handled in the browser using e.g. the HTML5 <eventsource> element or the EventSource JavaScript API.

var source = new EventSource('.../events');
source.addEventListener('message-to-client', function(e) {
  console.log(e.data);
}, false);
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
GeertPt
  • 16,398
  • 2
  • 37
  • 61
  • THAT is a good suggestion. I was so focussed on getting this done and I forgot about SSE. Thanks a lot for the answer and the example! – Apollo Oct 06 '20 at 19:22