I'm trying to find a way to avoid the IOException related to the fact that I read on a closed stream.
I'm calling a webservice method that returns a Stream:
InputStream stream = callRestWebService();
try {
parkingState = objectMapper.readValue(stream, ParkingState.class);
} catch (IOException e) {
throw new ParkingMeasurementProviderException("Could not retrieve data.", e);
}
Then, I have my Web Service method where I close the get connection:
public InputStream callRestWebService() {
int parkingId = 2803;
String endpointURL = REST_ENDPOINT + URI_INFO_PATH + parkingId + "/parkingState";
InputStream inputStream = null;
// Create an instance of HttpClient.
HttpClient httpclient = new HttpClient();
// Create a method instance.
GetMethod getMethod = new GetMethod(endpointURL);
getMethod.addRequestHeader("accept", "application/json");
try {
// Execute the method.
int statusCode = httpclient.executeMethod(getMethod);
inputStream = getMethod.getResponseBodyAsStream();
} catch (IOException e) {
e.printStackTrace();
} finally {
// Release the connection.
getMethod.releaseConnection();
}
return inputStream;
}
Is there a way to avoid having this exception without removing the : getMethod.releaseConnection();
The stack trace:
Disconnected from the target VM, address: '127.0.0.1:62152', transport: 'socket'
at be.ixor.itg.server.service.parking.hermesWS.HermesWSParkingControllerMeasurementProvider.getHermesMechelenData(HermesWSParkingControllerMeasurementProvider.java:126)
at be.ixor.itg.server.service.parking.hermesWS.Main.main(Main.java:14)
Caused by: java.io.IOException: Attempted read on closed stream.
at org.apache.commons.httpclient.AutoCloseInputStream.isReadAllowed(AutoCloseInputStream.java:183)
at org.apache.commons.httpclient.AutoCloseInputStream.read(AutoCloseInputStream.java:86)
at com.sun.org.apache.xerces.internal.impl.XMLEntityManager$RewindableInputStream.read(XMLEntityManager.java:2977)
at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.setupCurrentEntity(XMLEntityManager.java:702)
at com.sun.org.apache.xerces.internal.impl.XMLVersionDetector.determineDocVersion(XMLVersionDetector.java:186)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:772)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:737)
at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:119)
at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(DOMParser.java:232)
at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:284)
at javax.xml.parsers.DocumentBuilder.parse(DocumentBuilder.java:124)
at be.ixor.itg.server.service.parking.hermesWS.HermesWSParkingControllerMeasurementProvider.getHermesMechelenData(HermesWSParkingControllerMeasurementProvider.java:116)
... 1 more
Because you are calling releaseConnection() in your finally block, the input stream will no longer be available.
If you do not expect the content to be large, you could read the data from the input stream into a buffer and return the buffer instead of the input stream. Otherwise, you will need to change your code to allow the called to process the data from the input stream before releasing the connection.
BufferedReader br = new BufferedReader(new
InputStreamReader((response.getEntity().getContent())));
String response = br.readLine();
System.out.println("response" + response );
This code is working for me.
Related
I have an application that uses Spring Integration to send messages to a vendor application over TCP and receive and process responses. The vendor sends messages without a length header or an message-ending token and the message contains carriage returns so I have implemented a custom deserializer. The messages are sent as XML strings so I have to process the input stream, looking for a specific closing tag to know when the message is complete. The application works as expected until the vendor application is restarted or a port switch occurs on my application, at which time the CPU usage on my application spikes and the application becomes unresponsive. The application throws a SocketException: o.s.integration.handler.LoggingHandler : org.springframework.messaging.MessagingException: Send Failed; nested exception is java.net.SocketException: Connection or outbound has closed when the socket closes. I have set the SocketTimeout to be 1 minute.
Here is the connection factory implementation:
#Bean
public AbstractClientConnectionFactory tcpConnectionFactory() {
TcpNetClientConnectionFactory factory = new TcpNetClientConnectionFactory(this.serverIp,
Integer.parseInt(this.port));
return getAbstractClientConnectionFactory(factory, keyStoreName, trustStoreName,
keyStorePassword, trustStorePassword, hostVerify);
}
private AbstractClientConnectionFactory getAbstractClientConnectionFactory(
TcpNetClientConnectionFactory factory, String keyStoreName, String trustStoreName,
String keyStorePassword, String trustStorePassword, boolean hostVerify) {
TcpSSLContextSupport sslContextSupport = new DefaultTcpSSLContextSupport(keyStoreName,
trustStoreName, keyStorePassword, trustStorePassword);
DefaultTcpNetSSLSocketFactorySupport tcpSocketFactorySupport =
new DefaultTcpNetSSLSocketFactorySupport(sslContextSupport);
factory.setTcpSocketFactorySupport(tcpSocketFactorySupport);
factory.setTcpSocketSupport(new DefaultTcpSocketSupport(hostVerify));
factory.setDeserializer(new MessageSerializerDeserializer());
factory.setSerializer(new MessageSerializerDeserializer());
factory.setSoKeepAlive(true);
factory.setSoTimeout(60000);
return factory;
}
Here is the deserialize method:
private String readUntil(InputStream inputStream) throws IOException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
String s = "";
byte[] closingTag = CLOSING_MESSAGE_TAG.getBytes(ASCII);
try {
Integer bite;
while (true) {
bite = inputStream.read();
byteArrayOutputStream.write(bite);
byte[] bytes = byteArrayOutputStream.toByteArray();
int start = bytes.length - closingTag.length;
if (start > closingTag.length) {
byte[] subarray = Arrays.copyOfRange(bytes, start, bytes.length);
if (Arrays.equals(subarray, closingTag)) {
s = new String(bytes, ASCII);
break;
}
}
}
} catch (SocketTimeoutException e) {
logger.error("Expected SocketTimeoutException thrown");
} catch (Exception e) {
logger.error("Exception thrown when deserializing message {}", s);
throw e;
}
return s;
}
Any help in identifying the cause of the CPU spike or a suggested fix would be greatly appreciated.
EDIT #1
Adding serialize method.
#Override
public void serialize(String string, OutputStream outputStream) throws IOException {
if (StringUtils.isNotEmpty(string) && StringUtils.startsWith(string, OPENING_MESSAGE_TAG) &&
StringUtils.endsWith(string, CLOSING_MESSAGE_TAG)) {
outputStream.write(string.getBytes(UTF8));
outputStream.flush();
}
}
the inbound-channel-adapter uses the ConnectionFactory
<int-ip:tcp-inbound-channel-adapter id="tcpInboundChannelAdapter"
channel="inboundReceivingChannel"
connection-factory="tcpConnectionFactory"
error-channel="errorChannel"
/>
EDIT #2
Outbound Channel Adapter
<int-ip:tcp-outbound-channel-adapter
id="tcpOutboundChannelAdapter"
channel="sendToTcpChannel"
connection-factory="tcpConnectionFactory"/>
Edit #3
We have added in the throw for the Exception and are still seeing the CPU spike, although it is not as dramatic. Could we still be receiving bytes from socket in the inputStream.read() method? The metrics seem to indicate that the read method is consuming server resources.
#Artem Bilan Thank you for your continued feedback on this. My server metrics seem to indicate that they deserialize method is what is consuming the CPU. I was thinking that the SendFailed error occurs because of the vendor restarting their application.
Thus far, I have been unable to replicate this issue other than in production. The only exception I can find in production logs is the SocketException mentioned above.
Thank you.
I'm using Jersey Multipart for uploading file to the server via Rest API. In the resource method, I accessed the file content via InputStream. I want to return the uploaded file size to the client with EventOutput using SSE so the client easily get the uploaded file size directly from upload resource method.
I'm using Jersey as JAX-RS implementation in java with Grizzly Http server. Here is my code:
#POST
#Path("upload")
#Produces(SseFeature.SERVER_SENT_EVENTS)
#Consumes("multipart/form-data;charset=utf-8")
public EventOutput upload(#FormDataParam("file") InputStream file,
#FormDataParam("file") FormDataContentDisposition fileDisposition) {
final EventOutput eventOutput = new EventOutput();
try {
new Thread(new Runnable() {
#Override
public void run() {
try {
int read = -1;
byte[] buffer = new byte[1024];
OutboundEvent.Builder eventBuilder
= new OutboundEvent.Builder();
OutboundEvent event = null;
long totalRead = 0, lastReadMB = 0;
while ((read = file.read(buffer)) != -1) {
totalRead += read;
if (lastReadMB != (totalRead / (1024 * 1024))) {
lastReadMB = totalRead / (1024 * 1024);
event = eventBuilder.name("uploaded").data(Long.class, totalRead).build();
eventOutput.write(event);
}
}
event = eventBuilder.name("uploaded").data(Long.class, totalRead).build();
eventOutput.write(event);
} catch (Exception e) {
throw new RuntimeException(
"Error when writing the event.", e);
} finally {
try {
eventOutput.close();
} catch (Exception ioClose) {
throw new RuntimeException(
"Error when closing the event output.", ioClose);
}
}
}
}).start();
return eventOutput;
} catch (Exception e) {
logger.error(e.toString(), e);
}
throw new WebApplicationException(Response.status(Response.Status.INTERNAL_SERVER_ERROR).
entity("something happened").build());
}
The problem is when my resource method return EventOutput as a response and request processing thread back to the I/O container, the InputStream closed and the processing thread can't access to the uploaded file. Here is the exception:
Exception in thread "Thread-1" java.lang.RuntimeException: Error when writing the event.
at com.WebService.ContentService$1.run(ContentService.java:192)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.jvnet.mimepull.MIMEParsingException: java.io.IOException: Stream Closed
at org.jvnet.mimepull.WeakDataFile.read(WeakDataFile.java:115)
at org.jvnet.mimepull.DataFile.read(DataFile.java:77)
at org.jvnet.mimepull.FileData.read(FileData.java:69)
at org.jvnet.mimepull.DataHead$ReadMultiStream.fetch(DataHead.java:265)
at org.jvnet.mimepull.DataHead$ReadMultiStream.read(DataHead.java:219)
at java.io.InputStream.read(InputStream.java:101)
at com.WebService.ContentService$1.run(ContentService.java:181)
... 1 more
Caused by: java.io.IOException: Stream Closed
at java.io.RandomAccessFile.seek0(Native Method)
at java.io.RandomAccessFile.seek(RandomAccessFile.java:557)
at org.jvnet.mimepull.WeakDataFile.read(WeakDataFile.java:112)
... 7 more
1- What's the problem in the code? Why InputStream is closed in the middle of the file transfer?
2- Is there any alternative way to return the uploaded file size to the client in server side? (REQUIREMENT: the upload resource method must handle upload file asynchronously in different thread)
I am trying to reuse a Jersey2(Jersey 2.16) Client for async invocation. However after 2 requests, I see that the threads going into a waiting state, waiting on a lock. Since client creation is an expensive operation, I am trying to reuse the client in the async calls. The issue occurs only with ApacheConnectorProvider as the connector class. I want to use ApacheConnectorProvider, as I need to use a proxy and set SSL properties and I want to use PoolingHttpClientConnectionManager.
The sample code is given below:
public class Example {
Integer eventId = 0;
private ClientConfig getClientConfig()
{
ClientConfig clientConfig = new ClientConfig();
ApacheConnectorProvider provider = new ApacheConnectorProvider();
clientConfig.property(ClientProperties.REQUEST_ENTITY_PROCESSING,RequestEntityProcessing.BUFFERED);
clientConfig.connectorProvider(provider);
return clientConfig;
}
private Client createClient()
{
Client client = ClientBuilder.newClient(getClientConfig());
return client;
}
public void testAsyncCall()
{
Client client = createClient();
System.out.println("Testing a new Async call on thread " + Thread.currentThread().getId());
JSONObject jsonObject = new JSONObject();
jsonObject.put("value", eventId++);
invoker(client, "http://requestb.in/nn0sffnn" , jsonObject);
invoker(client, "http://requestb.in/nn0sffnn" , jsonObject);
invoker(client, "http://requestb.in/nn0sffnn" , jsonObject);
client.close();
}
private void invoker(Client client, String URI, JSONObject jsonObject)
{
final Future<Response> responseFuture = client.target(URI)
.request()
.async()
.post(Entity.entity(jsonObject.toJSONString(), MediaType.TEXT_PLAIN));
try {
Response r = responseFuture.get();
System.out.println("Response is on URI " + URI + " : " + r.getStatus());
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String args[])
{
Example client1 = new Example();
client1.testAsyncCall();
return;
}
}
The response I see is:
Testing a new Async call on thread 1
Response is on URI http://requestb.in/nn0sffnn : 200
Response is on URI http://requestb.in/nn0sffnn : 200
On looking at the thread stack, I see the following trace:
"jersey-client-async-executor-0" prio=6 tid=0x043a4c00 nid=0x56f0 waiting on condition [0x03e5f000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x238ee148> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2043)
at org.apache.http.pool.PoolEntryFuture.await(PoolEntryFuture.java:133)
at org.apache.http.pool.AbstractConnPool.getPoolEntryBlocking(AbstractConnPool.java:282)
at org.apache.http.pool.AbstractConnPool.access$000(AbstractConnPool.java:64)
at org.apache.http.pool.AbstractConnPool$2.getPoolEntry(AbstractConnPool.java:177)
at org.apache.http.pool.AbstractConnPool$2.getPoolEntry(AbstractConnPool.java:170)
Can someone give me a suggestion as to how to reuse Client objects for async requests and may be how to get over this issue as well.
I'm using Web API to stream large files to clients, but I'd like to log if the download was successful or not. That is, if the server sent the entire content of the file.
Is there some way to get a a callback or event when the HttpResponseMessage completes sending data?
Perhaps something like this:
var stream = GetMyStream();
var response = new HttpResponseMessage(HttpStatusCode.OK);
response.Content = new StreamContent(stream);
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
// This doesn't exist, but it illustrates what I'm trying to do.
response.OnComplete(context =>
{
if (context.Success)
Log.Info("File downloaded successfully.");
else
Log.Warn("File download was terminated by client.");
});
EDIT: I've now tested this using a real connection (via fiddler).
I inherited StreamContent and added my own OnComplete action which checks for an exception:
public class StreamContentWithCompletion : StreamContent
{
public StreamContentWithCompletion(Stream stream) : base (stream) { }
public StreamContentWithCompletion(Stream stream, Action<Exception> onComplete) : base(stream)
{
this.OnComplete = onComplete;
}
public Action<Exception> OnComplete { get; set; }
protected override Task SerializeToStreamAsync(Stream stream, TransportContext context)
{
var t = base.SerializeToStreamAsync(stream, context);
t.ContinueWith(x =>
{
if (this.OnComplete != null)
{
// The task will be in a faulted state if something went wrong.
// I observed the following exception when I aborted the fiddler session:
// 'System.Web.HttpException (0x800704CD): The remote host closed the connection.'
if (x.IsFaulted)
this.OnComplete(x.Exception.GetBaseException());
else
this.OnComplete(null);
}
}, TaskContinuationOptions.ExecuteSynchronously);
return t;
}
}
Then I use it like so:
var stream = GetMyStream();
var response = new HttpResponseMessage(HttpStatusCode.OK);
response.Content = new StreamContentWithCompletion(stream, ex =>
{
if (ex == null)
Log.Info("File downloaded successfully.");
else
Log.Warn("File download was terminated by client.");
});
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
return response;
I am not sure if there is direct signaling that all is ok, but you can use a trick to find out that the connection is exist just before you end it up, and right after you fully send the file.
For example the Response.IsClientConnected is return true if the client is still connected, so you can check something like:
// send the file, make a flush
Response.Flush();
// and now the file is fully sended check if the client is still connected
if(Response.IsClientConnected)
{
// log that all looks ok until the last byte.
}
else
{
// the client is not connected, so maybe have lost some data
}
// and now close the connection.
Response.End();
if the server sent the entire content of the file
Actually there is nothing to do :)
This might sound very simplistic but you will know if an exception is raised - if you care about server delivering and not client cancelling halfway. IsClientConnected is based on ASP.NET HttpResponse not the WebApi.
I have .NET Web Service and I am trying to use that web service from a Java Mobile phone. I am also using the NetBeans development environment with the web service tool kit. When I try to create the proxies, it falters on the enumerations stating that the simple types are not supported. Is there a way to describe the enumeration type in the WSDL so it is understandable to the toolkit?
// send a POST request to web server
public String sendPostRequest(String urlstring, String requeststring)
{
HttpConnection hc = null;
DataInputStream dis = null;
DataOutputStream dos = null;
String message = "";
// specifying the query string
String requeststring = "request=gettimestamp";
try
{
// openning up http connection with the web server
// for both read and write access
hc = (HttpConnection) Connector.open(urlstring, Connector.READ_WRITE);
// setting the request method to POST
hc.setRequestMethod(HttpConnection.POST);
hc.setRequestProperty("User-Agent","Profile/MIDP-2.0 Confirguration/CLDC-1.0");
hc.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
// obtaining output stream for sending query string
dos = hc.openDataOutputStream();
byte[] request_body = requeststring.getBytes();
// sending query string to web server
for (int i = 0; i < request_body.length; i++)
{
dos.writeByte(request_body[i]);
}
// flush outdos.flush();
// obtaining input stream for receiving HTTP response
dis = new DataInputStream(hc.openInputStream());
// reading the response from web server character by character
int ch;
while ((ch = dis.read()) != -1)
{
message = message + (char) ch;
}
}
catch (IOException ioe){
message = "ERROR";
}
finally{
// freeing up i/o streams and http connection
try{
if (hc != null)
hc.close();
}
catch (IOException ignored){}
try{
if (dis != null)
dis.close();
}
catch (IOException ignored){}
try{
if (dos != null)
dos.close();
}
catch (IOException ignored){}
}
return message;
}