This is a follow-up answer to supplement @harumph's excellent idea. All credit belongs to this person. I only wanted to provide a working example. I am stuck on an ancient version of Apache CXF with no hope of upgrade to latest Glassfish/Jersey. This is my "fake it until you make it". :)
public static final class FlushableHttpServletResponseOutputStream
extends OutputStream
{
private final OutputStream delegate;
private final HttpServletResponse response;
public FlushableHttpServletResponseOutputStream(OutputStream delegate, HttpServletResponse response)
{
this.delegate = ObjectArgs.checkNotNull(delegate, "delegate");
this.response = ObjectArgs.checkNotNull(response, "response");
}
@Override
public void write(int b)
throws IOException
{
delegate.write(b);
}
@Override
public void flush()
throws IOException
{
delegate.flush();
// Ref: https://stackoverflow.com/a/20708446/257299
response.flushBuffer();
}
}
@GET // or whatever you like
@Path("/your/url/path/here")
@Produces(MediaType.TEXT_PLAIN) // or whatever you like
public Response
httpGetStuff(@Context HttpServletResponse response) // auto-magically injected by CXF framework
throws Exception
{
// Ref: https://stackoverflow.com/a/63605927/257299
final StreamingOutput so = new StreamingOutput()
{
@Override
public void write(OutputStream os)
throws IOException, WebApplicationException
{
final FlushableHttpServletResponseOutputStream fos =
new FlushableHttpServletResponseOutputStream(os, response);
// Do something complex with 'fos' here.
// Call 'fos.flush()' to immediately send all buffered data via HTTP response chunk.
// Alternatively: You may call response.flush() directly.
}
};
final Response x = Response.ok(so).build();
return x;
}
For careful readers, you can find exactly where Apache CXF ignores a flush request here: org.apache.cxf.transport.http.AbstractHTTPDestination.WrappedOutputStream.flush()
(version 2.2.12):
public void flush() throws IOException {
//ignore until we close
// or we'll force chunking and cause all kinds of network packets
}