1

There is an infinite input stream and I read incomming massages with following simple lines of code:

InputStream inputStream = response.getBody();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
    while ((event = reader.readLine()) != null) {
        // do the work
    } 
}
System.out.println("Connection closed");

And everything is fine. But I want to be able to drop the connection if a certain amount of time there is no new messages.

The first problem was that readLine method blocks execution until the next message receiving. That's what I want to avoid. And I found this implementation of CloasableReader - wrapper over Bufferedreader that allows interrupting readLine from outside. So I just replaced BufferedReader with CloasableReader and voalá - I exited the while loop. But the line with "Connection closed" message still wasn't executed.

I changed the code a little bit...

InputStream inputStream = response.getBody();
BufferedReader reader = null;
try {
    reader = new BufferedReader(new InputStreamReader(inputStream));
    while ((event = reader.readLine()) != null) {
        // do the work
    } 
} finally {
    if (reader != null) {
        reader.close();
    }
}
System.out.println("Connection closed");

...and realized that actually close method also stucks waiting until next message receiving. Because of that Guava's TimeLimiter::callWithTimeout method didn't work for me. Actually it works fine (wrapping the code marked as "do the work" in the example above) but I cannot leave the try-catch-finaly block.

Internally BufferedReader::close calls InputStreamReader::close which calls InputStream::close and here is the problem. I'm just waiting and will do it forever.

I have no idea what to do now. How to force closing the stream?

micobg
  • 1,272
  • 6
  • 21
  • 35
  • The connection's **read-timeout** and [**connect-timeout**](https://docs.oracle.com/javase/10/docs/api/java/net/URLConnection.html#setConnectTimeout(int)) should have helped. – Joop Eggen Nov 28 '19 at 15:57
  • But how to access ```URLConnection``` object? I received ```ClientHttpResponse``` from ```RestTemplate::execute``` and I can get just ```InputStream```. – micobg Nov 29 '19 at 06:51
  • And also I don't want to close the connection a certain amount of time after opening but after receiving the last message. – micobg Nov 29 '19 at 07:47
  • what exception are you catching or declaring on the method? Both examples have `finally{}` but not `catch(){}`. If all you want to do is to execute that line with `System.out.println()` just place it in `finally{}` section. – diginoise Nov 29 '19 at 14:58

1 Answers1

1

Your problem looks very similar to this one. You can try to find clues there about callWithTimeout.

If your input stream is from some socket, you can try the version without callWithTimeout and add Socket.setSoTimeout, so it will throw java.net.SocketTimeoutException when reading from InputStream after specified number of milliseconds.

EDIT: Since you're using ClientHttpResponse, you can set read and connect timeout like so

    @Component
    public static class RestTemplateInitializer implements ApplicationListener<ApplicationReadyEvent> {

        public static HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory();

        @Override
        public void onApplicationEvent(ApplicationReadyEvent e) {
            clientHttpRequestFactory.setConnectTimeout(10000);
            clientHttpRequestFactory.setReadTimeout(10000);
        }


    }
stirante
  • 118
  • 8
  • Yes, the same problem. And as I can see there is no solution. :/ ```callWithTimeout``` works with ```readLine``` method but cannot help me with closing. – micobg Nov 29 '19 at 06:57
  • @micobg I updated the answer with a way to set read and connect timeout for `ClientHttpResponse` – stirante Nov 29 '19 at 14:41
  • Setting the read timeout solved my problem. The only difference was that I pass the request factory to RestTemplate's constructor. – micobg Dec 02 '19 at 06:44