users@jersey.java.net

[Jersey] Re: Unable to get ChunkedOutput to work properly using Tomcat 7

From: Marek Potociar <marek.potociar_at_oracle.com>
Date: Tue, 5 Nov 2013 17:54:31 +0100

Please try with the latest Jersey 2.5-SNAPSHOT.

I have not been able to reproduce the issue and as part of the evaluation I have fixed a minor bug in chunk parser as well as added support for setting a custom fixed chunk delimiter in the chunk output:
https://github.com/jersey/jersey/commit/b8aa8bdad30f8771ff336d83f2d6a780cbb8dd03

Marek
On 17 Oct 2013, at 00:11, Chun Tat David Chu <beyonddc.storage_at_gmail.com> wrote:

> Sure, my test application is actually fairly simple. Do you need it in particular format?
>
> I attached 4 files
> For the web service, you'll need
> AsyncPrototype.java
> Person.java
> web.xml
>
> For the client, you will need
> ChunkedInputTest.java
>
> Thanks,
>
> David
>
> On Wed, Oct 16, 2013 at 5:01 AM, Marek Potociar <marek.potociar_at_oracle.com> wrote:
> Hi David,
>
> We would need a reproducible test case to investigate further. Can you provide one?
>
> Thanks,
> Marek
>
> On Oct 12, 2013, at 3:41 AM, Chun Tat David Chu <beyonddc.storage_at_gmail.com> wrote:
>
>> Hi Marek,
>>
>> Thank you for your valuable insight. I spent a little more time to re-read the Jersey's tutorial, and I saw the following statements...
>> "Jersey provides several chunk parser implementation and you can implement your own parser to separate your chunks if you need. In our example above the default parser provided by Jersey is used that separates chunks based on presence of a \r\n delimiting character sequence."
>>
>> So I thought there is a default chunk parser in place if one is not provided or I misread the tutorial?
>>
>> I wrote a separate REST client using Apache HTTPComponents and when I enabled the debug, I see the following
>> HttpResponseHandlerImpl.setContentType(): application/json
>> HttpResponseHandlerImpl.setContentLength(): -1
>> 58495 [main] DEBUG org.apache.http.wire - << "24[\r][\n]"
>> 58495 [main] DEBUG org.apache.http.wire - << "{"firstName":"David","lastName":"0"}"
>> 58495 [main] DEBUG org.apache.http.wire - << "[\r][\n]"
>> 58495 [main] DEBUG org.apache.http.wire - << "24[\r][\n]"
>> 58495 [main] DEBUG org.apache.http.wire - << "{"firstName":"David","lastName":"1"}"
>> 58495 [main] DEBUG org.apache.http.wire - << "[\r][\n]"
>> 58495 [main] DEBUG org.apache.http.wire - << "24[\r][\n]"
>> 58495 [main] DEBUG org.apache.http.wire - << "{"firstName":"David","lastName":"2"}"
>> 58501 [main] DEBUG org.apache.http.wire - << "[\r][\n]"
>> 58501 [main] DEBUG org.apache.http.wire - << "0[\r][\n]"
>> 58501 [main] DEBUG org.apache.http.wire - << "[\r][\n]"
>> Based on those debug from the wire, it looks like each chunk contains a JSON object. If there is a default parser, how come the ChunkedInput.read() didn't return when a chunk is read but instead the ChunkedInput.read() was blocked until all the chunks are received?
>>
>> Thanks again!
>>
>> David
>>
>>
>> On Fri, Oct 11, 2013 at 5:51 PM, Marek Potociar <marek.potociar_at_oracle.com> wrote:
>>
>> On Oct 11, 2013, at 4:13 PM, Chun Tat David Chu <beyonddc.storage_at_gmail.com> wrote:
>>
>>> Hi Marek,
>>>
>>> My test code on ChunkedOuput is not much different than the one in the tutorial. It does write the chunk in a separate thread.
>>> It spawns a new thread, sits in a loop and return 20 JSON objects. I used the CountDownLatch just to make sure that the thread doesn't begin until the method returned (see below).
>>
>>>
>>> @PUT
>>> @Path("/asynchronous")
>>> @Produces(MediaType.APPLICATION_JSON)
>>> @Consumes(MediaType.APPLICATION_JSON)
>>> public ChunkedOutput<Person> getAsyncResponse(Person rep) {
>>>
>>> System.out.println("Received: " + rep);
>>>
>>> final CountDownLatch countDownLatch1 = new CountDownLatch(1);
>>>
>>> final ChunkedOutput<Person> output = new ChunkedOutput<Person>(String.class);
>>>
>>> new Thread() {
>>> public void run() {
>>> try {
>>>
>>> countDownLatch1.await();
>>> Thread.sleep(2000);
>>>
>>> for (int i = 0; i < 20; i++) {
>>>
>>> Person person = new Person("David",String.valueOf(i));
>>> output.write(person);
>>> Thread.sleep(1000);
>>> }
>>> } catch (Throwable th) {
>>> th.printStackTrace();
>>> } finally {
>>> try {
>>> output.close();
>>> } catch (IOException e) {
>>> // TODO Auto-generated catch block
>>> e.printStackTrace();
>>> }
>>> }
>>> }
>>> }.start();
>>>
>>> countDownLatch1.countDown();
>>>
>>> return output;
>>> }
>>>
>>> My test client side is also very simple. Followed the tutorial and it looks like this.
>>> ClientConfig clientConfig = new ClientConfig();
>>>
>>> Client client = ClientBuilder.newClient();
>>>
>>> final Response response = client.target("http://localhost:9080/jaxrs.prototype.tomcat7/rest/async/asynchronous").request(MediaType.APPLICATION_JSON).get();
>>>
>>>
>>> final ChunkedInput<String> chunkedInput =
>>> response.readEntity(new GenericType<ChunkedInput<String>>() {});
>>>
>>
>> I think the problem is here - you need to set ChunkedInput parser (via setParser(...)) to tell the chunk input where each chunk starts. For simple cases you can try to use ChunkInput.createParser(...) methods to create a fixed boundary delimiter parser. For anything more complex you may need to implement a ChunkParser yourself.
>>
>> Marek
>>
>>> String chunk = null;
>>> chunk = chunkedInput.read();
>>> while (chunk != null) {
>>> System.out.println("Next chunk received: " + chunk);
>>> chunk = chunkedInput.read();
>>> }
>>>
>>> I am just not sure why it is not receiving a chunk at a time until all the chunk is received then it print all 20 JSON objects at once.
>>>
>>> Thanks,
>>>
>>> David
>>>
>>> On Fri, Oct 11, 2013 at 4:43 AM, Marek Potociar <marek.potociar_at_oracle.com> wrote:
>>>
>>> On Oct 9, 2013, at 6:58 AM, Chun Tat David Chu <beyonddc.storage_at_gmail.com> wrote:
>>>
>>>> Hi All,
>>>>
>>>> I am trying to get ChunkedOutput to work using Tomcat 7. My test code is very similar to what's available on the tutorial website. https://jersey.java.net/documentation/latest/async.html#chunked-output
>>>
>>> What is the difference between your code and the tutorial?
>>>
>>>>
>>>> I tried with both command line curl and a Java application that follows ChunkedInput tutorial https://jersey.java.net/documentation/latest/async.html#d0e7470
>>>>
>>>> By observing the behavior, it appears to me that my Java application is not receiving the chunked output whenever my web service is invoking chunkedOutput.write(). Instead all the chunked output is received at once after all the write is completed.
>>>
>>> It appears to me as though you are not using a separate thread to write the chunked data and trying to write all the chunks BEFORE you return your chunked output. Is that the case?
>>>
>>> In order order to receive new chunks immediately, you must first return the chunked output from your method and only then start writing new chunks.
>>>
>>> Marek
>>>
>>>>
>>>> Any one tried using ChunkedOutput with Tomcat 7? Is there anything that I must configure? or I need to use a different web server?
>>>>
>>>> Thanks!
>>>>
>>>> David
>>>>
>>>
>>>
>>
>>
>
>
> <AsyncPrototype.java><ChunkedInputTest.java><Person.java><web.xml>