0

I am writing an application that provides a user-friendly GUI alternative to replace the current CLI users are using to communicate with remote devices. This application will send and receive all of the CLI I/O and convert it into easily understandable language for the user.

Since there is an open SSH connection between the application and the remote device at (almost) all times during execution, a background Thread is processing the InputStream from the remote side and caching it so that my application may use it.

The problem I am running into is that when I call for the cached data, it is always behind where it should be and then is displayed as such.

Background Thread Class

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;


public class ASAOutputStreamReader implements Runnable {

    public volatile boolean stopNow;
    private InputStream in;
    public volatile String opString;
    public volatile List<String> cachedOut = new ArrayList<String>();


    ASAOutputStreamReader(InputStream in) {

        this.in = in;

    }

    @Override
    public void run() {

        Scanner scan = new Scanner(in);
        while (true) {

            scan.useDelimiter("\r");
            opString = scan.next();
            System.out.println(opString);
            // Add processed output to cache
            cachedOut.add(opString);
            if (stopNow) {
                scan.close();
                break;
            }
        }//end while

    }
    /* getNAT() - List<String>
     * Method to return the cached strings
     * from the ASA console, up to the point
     * that the command was submitted
     * NOTE: THIS WILL RETURN IN REVERSE ORDER
     * But does not affect functionality
     */

    public synchronized List<String> getNAT() {
        List<String> str = new ArrayList<String>();
        if (cachedOut.isEmpty() == false) {
            for (int i = cachedOut.size()-1; i >= 0; i--) {
                if (cachedOut.get(i).contains("show run static")) {
                    break;
                }
                str.add(cachedOut.get(i));
            }
        }
        return str;
    }
}

UI Button & Method

send_btn.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    // Defined separately to ensure Thread safety
                    updateNAT(listNATs, ip_tf.getText());
                }
            });

private void updateNAT(final JTextArea jta, final String host) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                ACL1.sendCmd("show run static | include " + host + "\r");
                String str = "";
                for (String s : ACL1.asaOSMonitor.getNAT()) {
                    str = str.concat(s).concat("\n");
                }
                jta.setText(str);
            }
        });
    }

How can I guarantee that my data cache will be "up to date" before the call to update the UI to display it to the user?

  • For [example](http://stackoverflow.com/a/20603012/230513). – trashgod Aug 19 '14 at 16:56
  • I don't think you have a sequentialization problem. Your problem is that you construct a new Scanner to read every line. You're going to lose some output that way, because Scanner is buffered. Move the Scanner construction outside the loop. – user207421 Aug 19 '14 at 17:11
  • @EJP Done. This doesn't solve the issue in question, but I did actually have intermittent loss of output. I didn't even notice I had that line inside the loop and moving it out resolved that. Thank you! – Cold cup of Java Aug 19 '14 at 17:29
  • @trashgod I'm reading through that now. It looks like it may be what I'm looking for, in a way. Thank you – Cold cup of Java Aug 19 '14 at 17:51

1 Answers1

-1

Semaphores or any other concurrent synchronization mechanic (like for instance Critical_Sections in C++ for Win32 applications). You use the semaphore going into the threads where each thread grabs a specific semaphore and decrements it while incrementing the others respective semaphore. That is to say; Thread A grabs Semaphore A and decrements (<0) Semaphore A and increments Semaphore B (setting a flag state to say that it's ready for the other thread) Thread B grabs Semaphore B and decrements it, while incrementing Semaphore A.

Also you should probably not use Semaphores themselves as their performance is much slower than an actual critical section mechanic designed for multi-threading (I used Semaphores as the example because they are the most ubiquitous name throughout programming languages). Semaphores are meant to be used for system wide use.

http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Semaphore.html Java Semaphores