javaprocessconsole-applicationinteractionexternal-process

How to interact with a C console application from within my Java application


I know this has been asked before, but, as it happens to people sometimes, other answers didn't seem to help.

I need to start a C application and pass it a few inputs to navigate through its menu to finally execute what I need. The final output (result) is sent to a file, but the intermediate outputs (menu and sub-menus printed on the console) would be nice to have printed on my Eclipse console for debugging.

I wrote the following code based on what the user Vince posted on his question and later mentioned was working, but it doesn't seem to be doing it for me.

public final class InteractWithExternalApp {

    private static PrintWriter printOut;
    private static BufferedReader retrieveOutput;

    private static Process p;

    private EvaluationTests(){} // suppressing the class constructor

    public static void Evaluate(String paramToApp) {
        try
        {
            Runtime rt = Runtime.getRuntime() ;
            p = rt.exec("C:\\Path\\To\\Desktop\\appName " + paramToApp);
            InputStream in = p.getInputStream() ;
            OutputStream out = p.getOutputStream ();

            retrieveOutput = new BufferedReader(new InputStreamReader(in));
            printOut = new PrintWriter(out);

            // print menu
            if((line = retrieveOutput.readLine()) != null) {
            System.out.println(line);
            }

            // send the input choice -> 0
            printOut.println("0");
            printOut.flush();

            // print sub-menu
            if((line = retrieveOutput.readLine()) != null) {
                System.out.println(line);
            }

            // send the input choice
            printOut.println("A string");
            printOut.flush();

            // print sub-menu
            if((line = retrieveOutput.readLine()) != null) {
                System.out.println(line);
            }

            /*
                Repeat this a few more times for all sub-menu options until 
                the app finally executes what's needed
             */

        }catch(Exception exc){
            System.out.println("Err " + exc.getMessage());
        }

        return;
    }

Also, as an exercise, I tried opening Windows Command Prompt and sending it a command, following the example given here. cmd.exe opened fine, but then passing an echo command didn't do anything.

OutputStream stdin = p.getOutputStream();
InputStream stdout = p.getInputStream();

stdin.write(new String("echo test").getBytes());
stdin.flush();

Can anybody please land a hand? Where am I going wrong?


Solution

  • I don't want to say I'm 100% positive, but I am 99% convinced the problem was with the connection between input and output streams of the Java and the C programs. I was being able to start the program ok, but couldn't pass the parameters I needed.

    The solution indeed came by using ProcessBuilder. Thank you for instigating me to go back at the previous solution I had found, @Jayan.

    So here is the final code:

    public final class InteractWithExternalApp {
    
    private static BufferedReader inputReader, errorReader;
    private static OutputStream outputStream;
    private static PrintStream printOutputStream;
    
    private InteractWithExternalApp (){} // suppressing the class constructor
    
    public static void Evaluate(String paramToApp) {
        System.out.println("Running evaluation tests...");
    
        try
        {
            ProcessBuilder pb = new ProcessBuilder("Path/to/my/C/application", "paramToApp");
            pb.redirectOutput(Redirect.INHERIT);
            pb.redirectError(Redirect.INHERIT);
            Process process = pb.start();
    
            String line;
    
            errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
            while((line = errorReader.readLine()) != null){
                System.out.println(line);
            }
    
            inputReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            while((line = errorReader.readLine()) != null){
                System.out.println(line);
            }
    
            outputStream = process.getOutputStream();
            printOutputStream = new PrintStream(outputStream);
            printOutputStream.println("A parameter"); printOutputStream.flush();
            printOutputStream.println("Another parameter"); printOutputStream.flush();
            printOutputStream.println("And however many more I would need to finally get where I wanted"); printOutputStream.flush();
    
            inputReader.close();
            errorReader.close();
            printOutputStream.close();
    
        } catch(IOException ioe){
            System.out.println("Error during evaluation routine: " + ioe.getMessage());
        } finally {
            System.out.println("Evaluation complete!");
        }
    
        return;
    }
    

    Since I don't yet have enough reputation to "vote up" an answer, I formally express here my thanks to @Benjamin Gruenbaum and @samaitra, who posted their answers to this question, where I got the solution from.

    I hope this helps somebody else as well.