I had implemented streaming output in my Jersey Resource class.
@GET
@Path("xxxxx")
@Produces(BulkConstants.TEXT_XML_MEDIA_TYPE})
public Response getFile() {
FeedReturnStreamingOutput sout = new FeedReturnStreamingOutput();
response = Response.ok(sout).build();
return response;
}
class FeedReturnStreamingOutput implements StreamingOutput {
public FeedReturnStreamingOutput()
@Override
public void write(OutputStream outputStream) {
//write into Output Stream
}
}
The problem is eventhough a response is sent back from the resource before FeedReturnStreamingOutput is called Jersey client waits until FeedReturnStreamingOutput execution is completed.
Client Code :
Client client = Client.create();
ClientResponse response = webResource
//headers
.get(ClientResponse.class);
//The codes underneath executes after FeedReturnStreamingOutput is executed which undermines the necessity of streaming
OutputStream os = new FileOutputStream("c:\\test\\feedoutput5.txt");
System.out.println(new Date() + " : Reached point A");
if (response.getStatus() == 200) {
System.out.println(new Date() + " : Reached point B");
InputStream io = response.getEntityInputStream();
byte[] buff = new byte[1024000];
int count = 0;
while ((count = io.read(buff, 0, buff.length)) != -1) {
os.write(buff, 0, count);
}
os.close();
io.close();
} else {
System.out.println("Response code :" + response.getStatus());
}
System.out.println("Time taken -->> "+(System.currentTimeMillis()-startTime)+" ms");
Either your response is too small and never gets chunked so the server flushes the entire request at once. Or you have a server side issue were your jax-rs library is awaiting to have the complete stream before flushing.
However this looks more like a client problem. And you seem to be using an old version of jersey-client.
Also that
.get(ClientResponse.class)
looks fishy.Try using the JAX-RS standard as it is today (at least in the client):
While having jersey client 2.17 in the classpath:
The problem is the buffering
OutputStream
that Jersey uses to buffer the entity in order to determine the Content-Length header. The size of the buffer default to 8 kb. You disable the buffering if you want, or just change the size of the buffer, with the propertyHere's an example
Here's the result without setting the property
And here's the result after setting the property value to
0
Try invoking
outputStream.flush()
from the methodFeedReturnStreamingOutput.write(...)
every X number of bytes written to the output stream or something like that.I guess the buffer of the connection is not filled with the data you are returning. So the service does not return anything until Jersey invokes
outputStream.close()
.In my case, I have a service that streams data and I am doing it exactly as you: by returning
Response.ok(<instance of StreamingOutput>).build();
.My service returns data from a database and I invoke
outputStream.flush()
after writing each row to the output stream.I know that the service streams data because I can see the client begins receiving data before the service has finished sending the entire result.
I just realized that if you use a subclass of StreamingOutput, Jersey don't stream the response:
Is that a Jersey bug?