I\'m working on a setup that takes an http request (GET for testing purposes) to java servlet. How it works is, the ser let takes a request from the browser, parses it and
This is the most interesting line:
this.sc.send(msg, new HTTPServletResponseListener(response));
I suspect the sc
is this external TCP server you are calling and you are also passing a listener to be notified when the response arrives. Now the important assumption: am I right that the TCP server sends response asynchronously, notifying your listener in a different thread?
If this is the case, it explains your behaviour. In pre-3.0 servlets you had to handle the whole request within doGet
. Once your code leaves doGet()
, servlet container assumes the whole request has been handled and discards the request.
You have introduced a race condition: doGet()
returns without writing anything to the output stream. It takes few milliseconds for the container to handle the response and send it back. If during this short period of time your external TCP server returns data and notifies listener, the data will go through. But if the server is a bit slower, you are sending response to a connection that has already been handled.
Think about it this way: browser makes a call, doGet()
is called which in turns calls backend server. The doGet()
returns and servlet container assumes you are done. It sends back (empty) response and forgets about this request. Milliseconds or even seconds later response comes back from the back-end server. But the connection is gone, it has already been sent, sockets were closed, browser rendered the response. You are not telling your container: hey, wait, I haven't finished with that response!.
From worst to best:
Actively wait/poll for response in doGet()
.
Make your external TCP server call blocking. Change the TCP server facade so that it returns ResponseMessage
and move listener code to doGet()
. Example:
ResponseMessage responseMsg = this.sc.send(msg);
DataParser parser = new JSONParser();
String temp = parser.parseToString(responseMsg);
httpResponse.setContentType("application/json");
httpResponse.addHeader("Hmm","yup");
PrintWriter out = httpResponse.getWriter();
out.println(temp);
Use Servlet 3.0 asynchronous support, it is a much better choice in your use case and the scope of changes will be very limited.
In doGet()
:
final AsyncContext asyncContext = request.startAsync(request, response);
and in the HTTPServletResponseListener
once you're done:
asyncContext.complete();
The extra call to startAsync()
tells the container: even though I have returned from doGet()
, I haven't finished with this request. Please hold. I wrote an article about Servlet 3.0 some time ago.