0

Thank you for all your help. I tried everything from creating a new Thread. To changing around the way I use the writer.flush() and the writer.newLine(). It seems like the code keeps getting hung up at the while loop, constantly running the Thread.sleep() nonstop. I cannot provide the batch file because it is sensitive information, but the String command variable on top of the code is the path I am using to access the command. Please if you do answer this question please run the code first with test bat file and two input field.

Batch Script:

@ECHO OFF
SET /P _inputname= Please enter an name:
SET /P _inputpassword= Please enter an password:
IF "%_inputpassword%"=="1234" GOTO :they_said_1234

ECHO You entered the wrong password!
pause
GOTO 
:they_said_1234
ECHO You entered 1,2,3,4!
pause

Java Code:

  import java.io.*;
  import java.nio.CharBuffer;
  import java.util.ArrayList;


public class command{
public static void main(String[] args) {

    //String command="cmd /c d: && cd UPSDATA\\Virtualization Scripts\\EMC ESXi Grab\\EMC-ESXi-GRAB-1.3.7 && GRAB_RUN ";
    //String command="cmd /c date";
    String command = "cmd /c cd C:\\Users\\HFB2VZN\\Desktop\\folderG";

    try {
        Process process = Runtime.getRuntime().exec(command);
        try (Writer writer = new OutputStreamWriter(process.getOutputStream());
             Reader reader = new InputStreamReader(process.getInputStream())) {

            CharBuffer buf = CharBuffer.allocate(80);
            int tries = 2;

            while (process.isAlive()) {
                while (reader.ready() && reader.read(buf) > 0) {
                    //3
                   System.out.println("buf.flip() ran");
                    System.out.append(buf.flip());
                    buf.clear();
                }

                if (tries-- == 0) {
                    System.out.println("Destroyed");
                    process.destroy();
                    break;
                }
                //1
                writer.write("random");
                writer.flush();


                while (!reader.ready()) {
                    //2
                    System.out.println("while() loop, Thread runs in non stop loop");
                    Thread.sleep(800);

                }

            }
        }
    } catch (IOException | InterruptedException e) {
        e.printStackTrace();
    }


}

}`

Kane01
  • 61
  • 1
  • 1
  • 7
  • @Holger This is the bat file I am using – Kane01 Jul 05 '18 at 12:36
  • 1
    Your second `GOTO` has no target. You won’t see an error message as you’re not reading the error channel. – Holger Jul 05 '18 at 12:58
  • @Holger Yes, you are correct but unfortunately, this bat file is something cant change lol, I know it doesn't make sense. However, I just need a way to still work around it and make my java code input the two values and capture the result. Again Thanks for all your help Holger – Kane01 Jul 05 '18 at 13:33

1 Answers1

0

Compared to this example, executing a batch file will be much slower and having multiple commands may imply that there’s no available output for some time before the next output is generated. Not considering this may cause the loops get out of sync and after the process terminated, you must not execute the while (!reader.ready()) {…} loop without checking whether the process is still alive.

Since your batch file’s second GOTO lacks a target (it’s likely supposed to branch backwards), this batch file may terminal earlier than intended. Since no-one reads the error channel, this stays unnoticed. That could be the reason for hanging in that loop. Note further, that you are generating one input to the batch file per loop iteration, but have limited the number of iteration to 2 per tries variable. For a batch file expecting three inputs (name, password, pause), that’s too little.

The main problem is, there is no way to detect whether a subprocess is actually waiting for our input. This is what we have to work-around here. But a temporary stopping of producing output does not always imply that the program now waits for input.

I fixed your last GOTO to jump to the beginning of the batch file and used the following code to make two attempts entering the right password on the second.

try {
    Process process = Runtime.getRuntime().exec(command);
    try(Writer writer = new OutputStreamWriter(process.getOutputStream());
        Reader reader = new InputStreamReader(process.getInputStream())) {

        CharBuffer buf = CharBuffer.allocate(80);
        int tries = 2;
        while(process.isAlive()) {
            do {
                if(!buf.hasRemaining()) {
                    buf.flip();
                    buf = CharBuffer.allocate(buf.capacity()*2).put(buf);
                }
                do {} while(reader.ready() && reader.read(buf) > 0);
                if(buf.position() > 0) {
                    char c = buf.get(buf.position()-1);
                    if(c==':' || c=='.') break;
                }
                long deadLine = System.nanoTime() + TimeUnit.SECONDS.toNanos(1);
                for(long remaining = 1;
                        !reader.ready() && process.isAlive() && remaining > 0;
                        remaining = deadLine - System.nanoTime()) {
                    LockSupport.parkNanos(Math.min(
                        TimeUnit.MILLISECONDS.toNanos(100),
                        remaining));
                }
            } while(reader.ready());

            String input = buf.flip().toString();
            buf.clear();
            System.out.print(input);
            String value;
            if(input.endsWith("name:")) value = "aName";
            else if(input.endsWith("password:")) value = tries>1? "wrongPassword": "1234";
            else {
                value = "<any key>";
                tries--;
            }
            System.out.println("<- "+value);
            writer.write(value);
            writer.flush();
            if(tries == 0) {
                System.out.println("Destroying");
                process.destroy();
                break;
            }
        }
    }
} catch(IOException e) {
    e.printStackTrace();
}

Of course, if you can’t fix the GOTO statement, you have to provide the right password at the first attempt.

The code above will wait up to one second for the availability of new output, unless it recognizes one of the expected prompts in the output. And it won’t wait when the process is not alive anymore.

Holger
  • 285,553
  • 42
  • 434
  • 765