How to make an input to a started process with ProcessBuilder? - java

We have a closed-source archive that does only one thing: reads a string input and outs its value hashed. Not by its command arguments, but once it is started and stays continuously open, getting inputs and giving the value properly hashed.
So I want to open it with ProcessBuilder and do the inputs. The problem is that i have tried to input in the process and i have failed:
ProcessBuilder pb = new ProcessBuilder("/path/to/executable");
Process p = pb.start();
OutputStream os = p.getOutputStream();
PrintWriter pw = new PrintWriter(os);
pw.write("Hey\n");
String result = read(p);
System.out.println("Out: " + result);
p.destroy();
But looks like i'm not getting any output, first of because the executable is not getting my "Hey".
So the main question is, how do I input into the started program? Any kind of suggestions are welcome.

After
pw.write("Hey\n");
Try doing a
pw.flush();

Related

java ProcessBuilder: run program with multiple input

I use a ProcessBuilder to run system command from java. The system command may ask input data from user. Program failed when the system command asks input data from user for multiple times. Example of running such a command from command-line directly:
>test-input
Continue? Y/N
y
Entered y
Again: Continue? Y/N
y
Entered y
If I use my ProcessBuilder based program to run "test-input", it either hangs or failed to take input for a second time. Here is the code of reading/writing logic. Read from input stream (Exception handling and stream close logic is omitted)
ProcessBuilder pb = new ProcessBuilder(cmdList);
pb.redirectErrorStream(true);
pb.directory(new File("some-test-dir"));
process = pb.start();
InputStream is = process.getInputStream();
int value = -1;
while ( (value = is.read()) != -1) {
reader.append((char)value);
}
int result = process.waitFor();
Write to output stream:
public void write(String s) {
OutputStream os = null;
try {
os = process.getOutputStream();
os.write(s.getBytes(Charset.forName("UTF-8")));
}
catch (IOException e) {
//...
}
finally {
// Problematic
os.close();
}
}
The problem occurred at the line os.close(). If I put it there, the output stream is closed after the first input data is processed, thus it cannot be re-opened and program cannot take the second input data. If I do not close the output stream, then program hangs there as is.read() gets blocked forever. How to solve this issue? thanks
Problem is fixed by writing a new line character for each input, as described in: Writing to InputStream of a Java Process
os.write(s.getBytes(Charset.forName("UTF-8")));
os.write('\n');
os.flush();

Creating named pipes in Java

I am experimenting with creating named pipes using Java. I am using Linux. However, I am running into a problem where writing to the pipe hangs.
File fifo = fifoCreator.createFifoPipe("fifo");
String[] command = new String[] {"cat", fifo.getAbsolutePath()};
process = Runtime.getRuntime().exec(command);
FileWriter fw = new FileWriter(fifo.getAbsoluteFile());
BufferedWriter bw = new BufferedWriter(fw);
bw.write(boxString); //hangs here
bw.close();
process.waitFor();
fifoCreator.removeFifoPipe(fifo.toString());
fifoCreator:
#Override
public File createFifoPipe(String fifoName) throws IOException, InterruptedException {
Path fifoPath = propertiesManager.getTmpFilePath(fifoName);
Process process = null;
String[] command = new String[] {"mkfifo", fifoPath.toString()};
process = Runtime.getRuntime().exec(command);
process.waitFor();
return new File(fifoPath.toString());
}
#Override
public File getFifoPipe(String fifoName) {
Path fifoPath = propertiesManager.getTmpFilePath(fifoName);
return new File(fifoPath.toString());
}
#Override
public void removeFifoPipe(String fifoName) throws IOException {
Files.delete(propertiesManager.getTmpFilePath(fifoName));
}
I am writing a string that consists of 1000 lines. Writing 100 lines work but 1000 lines doesn't.
However, if I run "cat fifo" on an external shell, then the program proceeds and writes everything out without hanging. Its strange how the cat subprocess launched by this program doesn't work.
EDIT: I did a ps on the subprocess and it has the status "S".
External processes have input and output that you need to handle. Otherwise, they may hang, though the exact point at which they hang varies.
The easiest way to solve your issue is to change every occurrence of this:
process = Runtime.getRuntime().exec(command);
to this:
process = new ProcessBuilder(command).inheritIO().start();
Runtime.exec is obsolete. Use ProcessBuilder instead.
UPDATE:
inheritIO() is shorthand for redirecting all of the Process's input and output to those of the parent Java process. You can instead redirect only the input, and read the output yourself:
process = new ProcessBuilder(command).redirectInput(
ProcessBuilder.Redirect.INHERIT).start();
Then you will need to read the process's output from process.getInputStream().

Passing in path to another file to an exe run from inside a Java program

I'm writing a Java program, that needs to run an exe file compiled by cygwin. After running it, it needs to enter two lines of queries (each ending by \n). and on the third line it will receive an answer. I need to read that answer to process in the rest of the program.
The second line that I'm inputting is the path to another file! If I run the same command from CMD or from cygwin and input that path it works, but when I'm entering the path (hardcoding it in my Java program), the invoked exe file returns that there is no such file. Is there any special path instruction in this case?
(I have the following code which runs the program and gets the program output, but before getting my desired result, the exe gives an error that there is no such file and exits!
ProcessBuilder pb = new ProcessBuilder("C:/Users/Armen/Downloads/oll-0.03/oll_line.exe","P");
pb.redirectErrorStream(true);
Process cmd = pb.start();
PrintWriter pWriter = new PrintWriter(cmd.getOutputStream());
pWriter.println("L C:/Users/Armen/workspace/recurdom/model0fsupernew");
pWriter.flush();
//HERE IT GIVES ME THE ERROR
//pWriter.close();
InputStream is = cmd.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
line = br.readLine();
System.out.println("here received: "+line);
//pWriter.println("T +1 5:1 51:1 70:1 92:1 121:1 142:1 181:1 202:1 215:1 250:1 272:1 291:1 330:1 347:1 371:1 409:1 423:1 449:1 481:1 513:1 521:1 522:-1 523:-1 524:-1 525:-1 526:-1 527:-1 528:-1 529:-1 530:-1 539:1");
//pWriter.flush();

java getRuntime().exec() not working?

Basically, when I type these commands in
the terminal by hand, the sift program works and writes a .key file, but when I try to call it from my program, nothing is written.
Am I using the exec() method correctly? I have looked through the API and I can't seem to spot where I went wrong.
public static void main(String[] args) throws IOException, InterruptedException
{
//Task 1: create .key file for the input file
String[] arr = new String[3];
arr[0] = "\"C:/Users/Wesley/Documents/cv/final project/ObjectRecognition/sift/siftWin32.exe\"";
arr[1] = "<\"C:/Users/Wesley/Documents/cv/final project/ObjectRecognition/sift/cover_actual.pgm\"";
arr[2] = ">\"C:/Users/Wesley/Documents/cv/final project/ObjectRecognition/sift/keys/cover_actual.key\"";
String command = (arr[0]+" "+arr[1]+" "+arr[2]);
Process p=Runtime.getRuntime().exec(command);
p.waitFor();
BufferedReader reader=new BufferedReader(new InputStreamReader(p.getInputStream()));
String line=reader.readLine();
while(line!=null)
{
System.out.println(line);
line=reader.readLine();
}
}
The command line you are using is a DOS command line in the format:
prog < input > output
The program itself is executed with no arguments:
prog
However the command from your code is executed as
prog "<" "input" ">" "output"
Possible fixes:
a) Use Java to handle the input and output files
Process process = Runtime.getRuntime().exec(command);
OutputStream stdin = process.getOutputStream();
InputStream stdout = process.getInputStream();
// Start a background thread that writes input file into "stdin" stream
...
// Read the results from "stdout" stream
...
See: Unable to read InputStream from Java Process (Runtime.getRuntime().exec() or ProcessBuilder)
b) Use cmd.exe to execute the command as is
cmd.exe /c "prog < input > output"
You can't use redirections (< and >) with Runtime.exec as they are interpreted and executed by the shell. It only works with one executable and its arguments.
Further reading:
https://stackoverflow.com/a/11250789/105224
You cannot use input/output redirection with Runtime.exec. On the other hand, the same method returns a Process object, and you can access its input and output streams.
Process process = Runtime.exec("command here");
// these methods are terribly ill-named:
// getOutputStream returns the process's stdin
// and getInputStream returns the process's stdout
OutputStream stdin = process.getOutputStream();
// write your file in stdin
stdin.write(...);
// now read from stdout
InputStream stdout = process.getInputStream();
stdout.read(...);
I test, it's ok. You can try. Good luck
String cmd = "cmd /c siftWin32 <box.pgm>a.key";
Process process = Runtime.getRuntime().exec(cmd);
*For special characters that usually cause problems:
This code works correctly even with file names like: "1 - Volume 1 (Fronte).jpg"
String strArr[] = {"cmd", "/C", file.getCanonicalPath()};
Process p = rtObj.exec(strArr);///strCmd);
Agree too, redirection not supported here.
Tested on Windows 7
{guscoder:912081574}

Interact with Powershell process called from Java application

I'm trying to run a Java application which creates a new powershell process on startup and then later on interacts with it multiple times. Calling powershell.exe and have it execute a single command and return the output works fine for me. The problem arises if I don't want the powershell process to immediately finish/exit but to stay open so I can write to its outputStream and receive results back from the inputStream.
String input = "dir";
String[] commandList = {"powershell.exe", "-Command", "dir"};
ProcessBuilder pb = new ProcessBuilder(commandList);
Process p = pb.start();
if(input != null) {
PrintWriter writer = new PrintWriter(new OutputStreamWriter(new BufferedOutputStream(p.getOutputStream())), true);
writer.println(input);
writer.flush();
writer.close();
}
//p.getOutputStream().close();
Gobbler outGobbler = new Gobbler(p.getInputStream());
Gobbler errGobbler = new Gobbler(p.getErrorStream());
Thread outThread = new Thread(outGobbler);
Thread errThread = new Thread(errGobbler);
outThread.start();
errThread.start();
System.out.println("Waiting for the Gobbler threads to join...");
outThread.join();
errThread.join();
System.out.println("Waiting for the process to exit...");
int exitVal = p.waitFor();
System.out.println("\n****************************");
System.out.println("Command: " + "cmd.exe /c dir");
System.out.println("Exit Value = " + exitVal);
List<String> output = outGobbler.getOuput();
input = "";
for(String o: output) {
input += o;
}
System.out.println("Final Output:");
System.out.println(input);
This code returns the result of the "dir" command from a powershell - fine. But as you can see, I'm trying to run a second "dir" command using
PrintWriter writer = new PrintWriter(new OutputStreamWriter(new BufferedOutputStream(p.getOutputStream())), true);
writer.println(input);
writer.flush();
This has no effect whatsoever - no second dir output is shown when I run my code. I've also experimented with a powershell.exe option to open the powershell but not close it immediately:
String[] commandList = {"powershell.exe", "-NoExit", "-Command", "dir"};
But then my code hangs, meaning the Gobbler's who consume the process's inputStream don't read anything - strangely enough: they don't even read the first line - there must be at least some output....
I've also tried to close the process's outputStream after writing the second "dir" command to it - didn't change anything.
Any help is highly appreciated.
Thanks
Kurt
This sounds about right for the nature of a process spun up by another process. I think you're experiencing pretty standard behavior.
This is the key: p.waitFor()
From Java docs:
causes the current thread to wait, if necessary, until the process represented by this Process object has terminated.
You won't be able to receive the PowerShell output stream until it has terminated. When you run with -NoExit it never exits which is why you are experiencing the hang.
If you run ProcExp from Sysinternals you'll be able to see your Java process spin up an child PowerShell process.
So I don't think you'll be able to interact with it like it's a live object in memory.

Categories