I am facing quite an unusual situation. I have two Jboss (7.1) instances which communicate via HTTP. Instance A opens an HTTP connection to instance B and sends some data to be processed. The connection has timeout set, so after N seconds if no response is read it throws SocketTimeoutEception. Some cleanup is performed and the connection is closed. Instance B has a servlet, listening for such http requests and when one is received some computation is done. After that the response is populated and returned to the client.
The problem is that if the computation takes too much time, the client (A) will close the connection due to the time out, but server (B) will proceed as normal and will try to send the response after some time. I want to be able to detect that the connection is closed and do some house keeping, however I can't seem to be able to do that.
I have tried calling HttpServletResponse.flushBuffer(), but no exception is thrown. I have also explicitly set in the http request "Connection: close" to avoid persistent connection, but this had no effect. The http servlet resonse is processed as normal and disappears in the void without any exception. I do not know what I am doing wrong, I've read other questions on this site like:
Java's HttpServletResponse doesn't have isClientConnected method
Tomcat - Servlet response blocking - problems with flush
but they do not work in my case.
I think there might be something specific to the jboss servlet container, which causes to ignore or buffer the response, or perhaps the http connection is reused despite my efforts to close it from the client (A). I'd be happy if you could provide some pointers to where to look for the problem. I have spend several days on this and no relevant progress was made, so I need to resolve this urgently.
Here is the relevant code:
Client code (server A):
private static int postContent(URL destination, String fileName, InputStream content)
throws IOException, CRPostException
{
HttpURLConnection connection = null;
//Create the connection object
connection = (HttpURLConnection)destination.openConnection();
// Prepare the HTTP headers
connection.setDoOutput(true);
connection.setInstanceFollowRedirects(false);
connection.setRequestMethod("POST");
connection.setRequestProperty("content-type", "text/xml; charset=UTF-8");
connection.setRequestProperty("Content-Encoding", "zip");
connection.setRequestProperty("Connection", "close");//Try to make it non-persistent
//Timouts
connection.setConnectTimeout(20000);//20 sec timout
connection.setReadTimeout(20000);//20 sec read timeout
// Connect to the remote system
connection.connect();
try
{
//Write something to the output stream
writeContent(connection, fileName, content);
//Handle response from server
return handleResponse(connection);
}
finally
{
try
{
try
{
connection.getInputStream().close();//Try to explicitly close the connection
}
catch (Exception e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
connection.disconnect();//Close the connection??
}
catch (Exception e)
{
logger.warning("Failed to disconnect the HTTP connection");
}
}
}
private static int handleResponse(HttpURLConnection connection)
throws IOException, CRPostException
{
String responseMessage = connection.getResponseMessage();//Where it blocks until server returns the response
int statusCode = connection.getResponseCode();
if (statusCode == HttpURLConnection.HTTP_OK)
{
logger.debug("HTTP status code OK");
InputStream in = connection.getInputStream();
try
{
if (in != null)
{
//Read the result, parse it and return it
....
}
}
catch (JAXBException e)
{
}
}// if
//return error state
return STATE_REJECTED;
}//handleResponse()
Server code (Server B):
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
String crXML = null;
MediaType mediaType = null;
Object result;
// Get the media type of the received CR XML
try
{
mediaType = getMediaType(request);
crXML = loadDatatoString(mediaType, request);
result = apply(crXML);
}
catch (Exception e)
{
logger.error("Application of uploaded data has failed");
//Return response that error has occured
....
return;
}
// Finally prepare the OK response
buildStatusResponse(response, result);
// Try to detect that the connection is broken
// and the resonse never got to the client
// and do some housekeeping if so
try
{
response.getOutputStream().flush();
response.flushBuffer();
}
catch (Throwable thr)
{
// Exception is never thrown !!!
// I expect to get an IO exception if the connection has timed out on the client
// but this never happens
thr.printStackTrace();
}
}// doPost(..)
public static void buildStatusResponse(HttpServletResponse responseArg, Object result)
{
responseArg.setHeader("Connection", "close");//Try to set non persistent connection on the response too - no effect
responseArg.setStatus(HttpServletResponse.SC_OK);
// write response object
ByteArrayOutputStream respBinaryOut = null;
try
{
respBinaryOut = new ByteArrayOutputStream();
OutputStreamWriter respWriter = new OutputStreamWriter(respBinaryOut, "UTF-8");
JAXBTools.marshalStatusResponse(result, respWriter);
}
catch (Exception e)
{
logger.error("Failed to write the response object", e);
return;
}
try
{
responseArg.setContentType(ICRConstants.HTTP_CONTENTTYPE_XML_UTF8);
responseArg.getOutputStream().write(respBinaryOut.toByteArray());
}
catch (IOException e)
{
logger.error("Failed to write response object in the HTTP response body!", e);
}
}//buildStatusResponse()