ChunkedInput not working in jersey

1.9k views Asked by At

Can anyone help me why the java code is having issue and printing all data in one go instead of prinitng each chunk as javascript code

Java Code :

import org.glassfish.jersey.client.ChunkedInput;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.core.GenericType;
import javax.ws.rs.core.Response;

public class RunClient {

    public static void main(String args[]) throws InterruptedException {
        Client client = ClientBuilder.newClient();
//2 is to increase amount of data and 3(seconds) is for time b/w chunked output  ,can be changed
        final Response response = client.target("http://jerseyexample-ravikant.rhcloud.com/rest/jws/streaming/2/3").request()
                .get();
        final ChunkedInput<String> chunkedInput = response.readEntity(new GenericType<ChunkedInput<String>>() {
        });
        String chunk;
        while ((chunk = chunkedInput.read()) != null) {
            System.err.println("Next chunk received: " );
            System.out.println(chunk);
        }


    }
}

JavaScript : (Open Page http://jerseyexample-ravikant.rhcloud.com/rest/jws and then press F12 and run below in console as javascript call not allowed from other domain)

//2 is to increase amount of data and 3(seconds) is for time b/w chunked output  ,can be changed

var xhr = new XMLHttpRequest()
xhr.open("GET", "http://jerseyexample-ravikant.rhcloud.com/rest/jws/streaming/2/3", true)
xhr.onprogress = function () {
  console.log("PROGRESS:", xhr.responseText) ;console.log("\n");
}
xhr.send()

EDIT : Just for help it also works will normal java connection

        String uri = "http://jerseyexample-ravikant.rhcloud.com/rest/jws/streaming/3/1";
        URL url = new URL(uri);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setRequestMethod("GET");
        connection.setDoOutput(true);
        BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
        String line;
        while ((line = in.readLine()) != null) {
            System.out.println(line);
        }
        in.close();

My WebService Code

@Path("streaming/{param}/{sleepTime}")
@GET
@Produces(MediaType.TEXT_PLAIN)
public ChunkedOutput<String> getChunkedStream(@PathParam("param") String loopcount,@PathParam("sleepTime") String sleepTime) throws Exception {

    final ChunkedOutput<String> output = new ChunkedOutput<>(String.class);
    final Integer val=Integer.parseInt(loopcount);
    final Integer isleepTime=Integer.parseInt(sleepTime)*1000;
    new Thread(new Runnable() {

        @Override
        public void run() {
            try {
                StringBuffer chunk = null;

                for (int i = 0; i < 10; i++) {
                        chunk = new StringBuffer();
                    for (int j = 0; j < val; j++) {
                        chunk.append(" Message #" + i+ "#"+j);
                    }
                        output.write(chunk.toString()+"\n");
                    System.out.println("write");
                    Thread.sleep(isleepTime);
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    System.out.println("output.close();");
                    output.close();
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
        }
    }).start();

    return output;
}
1

There are 1 answers

2
galusben On BEST ANSWER

Form jersey docs:

Writing chunks with ChunkedOutput is simple, you only call method write() which writes exactly one chunk to the output. With the input reading it is slightly more complicated. The ChunkedInput does not know how to distinguish chunks in the byte stream unless being told by the developer. In order to define custom chunks boundaries, the ChunkedInput offers possibility to register a ChunkParser which reads chunks from the input stream and separates them. 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 your server has to separate chunks with \r\n, or you have to register a ChunkParser.

Assuming you have a constant finalising each chunk you could try:

Client client = ClientBuilder.newClient();
//2 is to increase amount of data and 3(seconds) is for time b/w chunked output  ,can be changed
        final Response response = client.target("http://jerseyexample-ravikant.rhcloud.com/rest/jws/streaming/2/3").request()
                .get();
        final ChunkedInput<String> chunkedInput = response.readEntity(new GenericType<ChunkedInput<String>>() {
        });
        chunkedInput.setParser(ChunkedInput.createParser(BOUNDARY));
        String chunk;
        while ((chunk = chunkedInput.read()) != null) {
            System.err.println("Next chunk received: " );
            System.out.println(chunk);
        }

While BOUNDARY is a finalizing string for each chunk. The in.readLine solution in your edit will break down "chunks" by every newline, even if one chunk consist a \n, it will be interpreted as 2 chunks.