0

My method checkConnection() calls setPort() within a TimeLimiter which exits the call method within 3 seconds if the method isn't finished. This works great and there is an exception of com.google.common.util.concurrent.UncheckedTimeoutException when the time limit is exceeded. However even after this exception is thrown setPort still runs and once completed, code within my try statement opening the port runs however once it gets to Thread.sleep(100) an InterruptedException is thrown then the method exits. However this leaves me with an open port which causes problems. Is there a way once the time limit is exceeded that all code within the call() method will stop?

 public static String checkConnection(final String comPort) {

        final String port = comPort;
        String result = null;

        TimeLimiter limiter = new SimpleTimeLimiter();
        try {

            result = limiter.callWithTimeout(new Callable<String>() {

                public String call() {

                    // Try to set serial port
                    String setPort = setPort(comPort);

                    // Check for any exceptions
                    if(setPort.contains("jssc.SerialPortException")) {

                        if(setPort.contains("Port busy")) {

                            return "Error: The port appears to be busy";

                        } else {

                            return "Error: Can't connect to port";

                        }

                    }

                    try {

                            // Port can't be accessed twice at the same time
                            synchronized(portLock) {

                                // Open port if not already opened
                                if(!serialPort.isOpened())
                                    serialPort.openPort();

                                // Sleep while response is being sent
                                Thread.sleep(300);

                                // Check for response
                                buffer = serialPort.readBytes(6);//Read 6 bytes from serial port

                                serialPort.closePort();

                            }

                        // Parse response as string
                        response = new String(buffer);

                    } catch (SerialPortException | InterruptedException e) {

                        System.out.println("Serial:: ping() :: Exception while pinging Noteu : " + e);

                        return "Error";

                    }

                    return response;

                }
              }, 3, TimeUnit.SECONDS, false);

        } catch (Exception e) {

            System.out.println("Serial:: checkConnection() :: Exception while calling ping : " + e);

        }

    } 



public static String setPort(String port) {

        synchronized(portLock) {

            try {

                System.out.println("Serial:: setPort() :: Opening Port...");

                serialPort = new SerialPort(port);

                if(!serialPort.isOpened())
                    serialPort.openPort();

                System.out.println("Serial:: setPort() :: Setting Params...");

                serialPort.setParams(SerialPort.BAUDRATE_9600, 
                        SerialPort.DATABITS_8,
                        SerialPort.STOPBITS_1,
                        SerialPort.PARITY_NONE);
                System.out.println("Setting Port3");

                serialPort.closePort();

                System.out.println("Serial:: setPort() :: Port Set...");

                return "Success";

            } catch (SerialPortException e) {

                System.out.println("Serial:: setPort() :: Exception at set Port : " + e.toString());

                return e.toString();

            }

        }

    }
Jack Trowbridge
  • 3,175
  • 9
  • 32
  • 56

2 Answers2

1

Can you try if this works This is the signature of

callWithTimeout(Callable<T> callable,
                long timeoutDuration,
                TimeUnit timeoutUnit,
                boolean amInterruptible)

........
amInterruptible - whether to respond to thread interruption by aborting the operation and throwing InterruptedException; if false, the operation is allowed to complete or time out, and the current thread's interrupt status is re-asserted.

You are passing amInterruptible as false.Can you try passing true and see if it works .Also I have strong feeling setPort has to be interruptible .For that as User Scadge has commented you need to provide its implementations.Anyways just hoping this quick solution might work for you

Abhijeet Kushe
  • 2,477
  • 3
  • 26
  • 39
  • I've added the set port method to my code. I've tried that however it doesn't seem to work. Even after the time limit is up all code runs normally until it hits the Thead.sleep(100) where it is interrupted however I want the code to stop immediately. – Jack Trowbridge Dec 21 '14 at 17:56
  • At the end of setPort you can add this check if(Thread.interrupted()){ serialPort.close(); throw new InterruptedException() } and in the catch block of the method which calls setPort close the port if set.This will make the setPort interruptible which ideally is desirable as you want any of your clients to who call setPort to reap benefits from it – Abhijeet Kushe Dec 21 '14 at 18:18
  • It will throw a compilation error you will have to declare the method setPort to throw InterruptedException.As setPort is a public and static method I believe many clients can call this method so I suggested this .If it was a private method then this was not needed – Abhijeet Kushe Dec 21 '14 at 18:20
  • How do I declare setPort to throw InterruptedException and catch the exception? When I try to add throws InterruptedException and add "InterruptedException e" to my catch block I get the error "Unreachable catch block for InterruptedException" – Jack Trowbridge Dec 21 '14 at 18:33
  • If you are going to catch the exception in the same method then don't throw or declare just close the serialPort – Abhijeet Kushe Dec 21 '14 at 18:48
1

This is the documented behavior of SimpleTimeLimiter:

A TimeLimiter that runs method calls in the background using an ExecutorService. If the time limit expires for a given method call, the thread running the call will be interrupted.

Basically, "interrupting" a thread means that its interrupt flag is set (unless one of the conditions mentioned in the Thread.interrupt() documentation holds). So the flag is just set, without any exceptions thrown within the internal thread (the thread that performs the setPort.

Once that thread gets to the point where it calls sleep(), then the interrupt flag is read and immediately aborts the thread.

What you could do is check the Thread.interrupted() or Thread.isInterrupted() methods, and if there was an interruption, clean up the port (close it, etc.). You could put the whole thing inside the try that catches InterruptedException, and throw InterruptedException if Thread.interrupted() is true after each long operation you perform - setPort, openPort, etc.

In fact, it would be best to do this as early as possible, so maybe inside the implementation of setPort, if it's possible.

RealSkeptic
  • 33,993
  • 7
  • 53
  • 79
  • I've added if(Thread.interrupted()){ serialPort.closePort(); throw new InterruptedException(); } after the setPort method which does stop the code. However code running within the setPort method still runs and once the port is set I can't reset it or I get a port busy exception. I can't use Thread.interrupted() within the setPort method its self as its unreachable code. – Jack Trowbridge Dec 21 '14 at 18:30
  • If you declare it as `throws InterruptedException` you also need to check after each step of the port manipulation, and throw an actual `InterruptedException`, otherwise the `catch` code is unreachable. As for the fact that you can't reset it - you should probably give the full stack trace you get. – RealSkeptic Dec 21 '14 at 18:50