Java ProcessBuilder inconsistent values when reading from another java program - java

I have a class which is run in its own process via ProcessBuilder. It just reads input & writes it back and exits if we send it EXIT
public class SubProcess
{
public static void main(String[] args)throws Exception
{
try(BufferedReader reader=new BufferedReader(new InputStreamReader(System.in)))
{
String line;
while((line=reader.readLine())!=null)
{
if(line.equalsIgnoreCase("EXIT"))
{
System.out.println("Process Exiting");
break;
}
else{System.out.println("Echoing:"+line);}
}
}
}
}
This is located in D:/Process an empty directory in my system
Then in my netbeans IDE i run it as an process by first compiling this file and then running it
public class ParentProcess
{
public static void main(String[] args)throws Exception
{
ProcessBuilder builder=new ProcessBuilder("javac","SubProcess.java");
builder.directory(new File("D:/Process"));
//compile the program
Process process=builder.start();
InputStream error=process.getErrorStream();
if(error!=null)
{
try(error)
{
byte[] data=new byte[1024];
int len;
while((len=error.read(data))>0){System.err.println(new String(data,0,len));}
}
}
//start the program
builder.command("java","SubProcess");
builder.redirectOutput(ProcessBuilder.Redirect.INHERIT);
process=builder.start();
try(BufferedReader input=process.inputReader();
OutputStream output=process.getOutputStream();
BufferedReader consoleInput=new BufferedReader(new InputStreamReader(System.in)))
{
System.out.println("Begin");
String line;
while((line=consoleInput.readLine())!=null)
{
System.out.println("Writing Output");
output.write((line+"\n").getBytes("UTF-8"));
output.flush();
System.out.println("Reading Input");
String response=input.readLine();
System.out.println(response);
if(response!=null && response.equalsIgnoreCase("Process Exiting"))
{
System.out.println("Exiting");
break;
}
}
}
}
}
I face 2 problems
I first get a null value then the response from the process
Hello
Writing Output
Reading Input
null
Echoing:Hello
World
Writing Output
Reading Input
null
Echoing:World
Parent Process doesnt exit even if i write EXIT to the process. The child process exits normally but the response.equalsIngoreCase("Process Exiting") is never executed
Begin
EXIT
Writing Output
Reading Input
null
Process Exiting
It never prints Exiting
How do i fix this?

Related

How to input in a program running in cmd using java

I'm creating a program that will accept source codes, compile it, and input test cases to see whether the program was correct. A source code checker, if you may. What I used for compiling programs is through cmd. My problem now is how to enter the test cases once the programs are running in cmd.
This is actually a program for our school. So the professor will give a problem (ex. Input an integer, say if it's even or odd) then this program will check the students' source codes by testing the test cases provided by the professor (ex. input: 1 output: odd, input 2: output: even).
Here's my sample code (c# compiler)
case ".cs":
CsCompiler();
Run(path + "\\program");
break;
My functions:
public static void CsCompiler() throws IOException, InterruptedException {
Process(path + "\\", " c:\\Windows\\Microsoft.NET\\Framework\\v3.5\\csc /out:program.exe *.cs");
}
public static void Process(String command, String exe) throws IOException, InterruptedException {
final Process p;
if (command != null) {
p = Runtime.getRuntime().exec(exe, null, new File(command));
} else {
p = Runtime.getRuntime().exec(exe);
}
new Thread(new Runnable() {
public void run() {
BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = null;
try {
while ((line = input.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
p.waitFor();
}
public static void Run(String command) throws IOException, InterruptedException {
String[] argss = {"cmd", "/c", "start", command};
ProcessBuilder pb;
pb = new ProcessBuilder(argss);
pb.start();
}
If I got you right you want to start a program and fetch its output while injecting input from your java method. Actually thats very simple since you already did the ouput fetching in your compile method.
The Process Class also has a getOutputStream method that you can use for injecting input to your process.
I will show how to do this with an example.
Consider this simple C programm as a students source code that takes a number as input and checks if it is even or odd.
#include <stdio.h>
int main(){
int x;
printf("Enter an Integer Number:\n");
if (( scanf("%d", &x)) == 0){
printf("Error: not an Integer\n");
return 1;
}
if(x % 2 == 0) printf("even\n");
else printf("odd\n");
return 0;
}
Now implement your Run method like this to run the application, inject input, read output and check the return value.
public static void Run(String command, String input) throws IOException, InterruptedException {
// create process
String[] argss = {"cmd", "/c", command};
ProcessBuilder pb = new ProcessBuilder(argss);
Process process = pb.start();
// create write reader
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
// write input
writer.write(input + "\n");
writer.flush();
// read output
String line = "";
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
// wait for process to finish
int returnValue = process.waitFor();
// close writer reader
reader.close();
writer.close();
System.out.println("Exit with value " + returnValue);
}
And thats it. If you invoke this method like this
Run("NumberChecker.exe", "1");
Run("NumberChecker.exe", "2");
Run("NumberChecker.exe", "a");
You will get the following output
Enter an Integer Number:
odd
Exit with value 0
Enter an Integer Number:
even
Exit with value 0
Enter an Integer Number:
Error: not an Integer
Exit with value 1

Sending input to a running JAR via Java process

I want to write a program which executes JARs and gets their output.
When the JAR program has only a print statement it works fine, but when it asks for input during execution, the program freezes.
Code of the JAR file program:
import java.util.*;
public class demo {
public static void main(String r[]) {
Scanner sc = new Scanner(System.in);
System.out.println("Hello ...");
System.out.println("please enter the number :");
int i = sc.nextInt();
System.out.println(" number : " + i);
}
}
Code of the original program which runs the JAR files:
public class jartorun {
public static void main(String arg[]) throws IOException {
String t = "javaw -jar D:\\jarcheck\\temp.jar";
Process p = Runtime.getRuntime().exec(t);
BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = "";
while ((line = input.readLine()) != null) {
System.out.print(line + "\n");
}
input.close();
}
}
I can give input to the JAR using process.getOutputStream(), but how would I use it so I can create a program which can give input to a JAR and read its output simultaneously?
If you want to run stuff outside the VM use the ProcessBuilder. Works fine for me and you can inherit the IO Stream.
ProcessBuilder builder = new ProcessBuilder("./script.sh",
"parameter1");
builder.directory(new File("/home/user/scripts/"));
builder.inheritIO();
try {
Process p = builder.start();
p.waitFor();
// Wait for to finish
} catch (InterruptedException e) {
e.printStackTrace();
} catch (IOException ioe) {
ioe.printStackTrace();
}
This should also work with Windows batch scripts and paths.
(haven't tried the input though)
You can use p.getOutputStream() to provide input to the launched process.

Multiprocess via processbuilder Communication, freeze at readline() for BufferedReader()

I am trying to allow communication between one program (the program launcher, if you will) and the programs it launches via processbuilder. I have the output working fine, but the input seems to stop when it reaches the readline() method in helloworld (the created process).
Below is helloworld.java:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Scanner;
public class helloworld {
public static void main (String[] args) {
System.out.println ("println(\"Hello World!\")");
System.out.println ("getInput()");
Scanner in = new Scanner(System.in);
BufferedReader br = new BufferedReader(
new InputStreamReader(System.in));
String input = "";
try {
// wait until we have data to complete a readLine()
while (!br.ready()) {
Thread.sleep(200);
}
System.out.println("println(\"Attempting to resolve input\")");
input = br.readLine();
^This is where program hangs^
if(input != null){
System.out.println("println(\"This should appear\")");
}
System.out.println("println(\"input recieved " + input + "\")");
} catch (InterruptedException | IOException e) {
System.out.println("ConsoleInputReadTask() cancelled");
}
System.out.println("println(\"You said: " + input + "\")");
//System.out.println("println(\"You said: " + in. + "!\")");
in.close();
System.exit(0);
}
}
This is where the output (println) from the other process is recieved:
public void run() {
try {
//cfile = files[indexval].getAbsolutePath();
String[] commands =
{
"java", //Calling a java program
"-cp" , //Denoting class path
cfile.substring(0,cfile.lastIndexOf(File.separator) ), //File path
program}; //Class name
ProcessBuilder probuilder = new ProcessBuilder( commands );
//start the process
Process process = probuilder.start();
//Read out dir output
//probuilder.inheritIO(); //Can inherit all IO calls
InputStream is = process.getInputStream();
OutputStream os = process.getOutputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os));
BufferedReader br = new BufferedReader(isr);
String line;
/*System.out.printf("Output of running %s is:\n",
Arrays.toString(commands));*/
while ((line = br.readLine()) != null) {
myController.runCommand(line, "Please enter something!", bw);
//System.out.println(line);
}
br.close();
os.close();
} catch (IOException e){
e.printStackTrace();
}
System.out.println("programclosed");
}
And here is the function that it calls:
public synchronized void runCommand(String line, Object... arguments) throws IOException {
String[] tokens;
if(line.contains("(")){
tokens = line.split("\\(",2);
switch(tokens[0]){
case "println": //Println - format println(String strng)
tokens[1] = tokens[1].substring(1, tokens[1].length() - 2);
System.out.println(tokens[1]);
break;
case "getInput": //Get input - format getInput(String command, String message, BufferedWriter br)
Scanner reader = new Scanner(System.in);
System.out.println(arguments.length);
System.out.println(((String)arguments[0]));
BufferedWriter in = ((BufferedWriter)arguments[1]);
in.write(reader.nextLine());
System.out.println("sending input");
in.flush();
reader.close();
break;
default:
System.out.println("Invalid command recieved!");
}
} else
System.out.println("Invalid command recieved!");
}
The output I recieve is:
Hello World!
2
Please enter something!
This is a test input
sending input
Attempting to resolve input
As you can see, I successfully exit the while(!br.ready()) loop, and I stop at br.readLine();
I am aware inheritIO() exist, but for this case I am using the BufferedOuput to send commands which are then parsed and sent to the switch statement, which in turn calls the corresponding function. This is because multiple processes could be launched from the process manager, think of the fun when multiple System.in calls arrive, with nothing to determine which process it is for! In addition, this allows for me to call any type of function, even those not related to println or input.
I believe the issue here is a result of the following:
BufferedReader.ready() returns true if there are any characters available to be read. It does not guarantee that there are any carriage returns among them. (docs)
BufferedReader.readLine() looks for a carriage return to complete a line. If one is not found, it blocks.
BufferedWriter.write() does not automatically write a terminating carriage return.
To test whether this is actually the problem, replace this line in runCommand():
in.write(reader.nextLine());
with:
in.write(reader.nextLine() + "\n");

Using Runtime.getRuntime().exec in eclipse

I'm using Runtime.getRuntime().exec in eclipse to run another java program from the current program.
I've used the following code.
InputStreamReader isr=new InputStreamReader(System.in);
BufferedReader br=new BufferedReader(isr);
System.out.println("Enter the class name");
String s=br.readLine();
String str="XYZ";
String[] cmd = {"java","-cp", "C:/Users/..../workspace/Testing/bin",s,str};
Process pro=Runtime.getRuntime().exec(cmd);
I'm also passing a string "XYZ" to that program. That program just accepts the string and displays
Your string is XYZ
But by using the line
String[] cmd = {"java","-cp",
"C:/Users/..../workspace/Testing/bin",s,str};
i'm able to run the program but it is not accepting any arguments. It is neither displaying the output nor showing any errors.
Where am i going wrong?
Consider the program to be called is
import java.io.*;
public class Test
{
public static void main(String[] args) throws IOException
{
InputStreamReader isr=new InputStreamReader(System.in);
BufferedReader br=new BufferedReader(isr);
System.out.println("Enter any string");
String s=br.readLine();
System.out.println("Your string is "+s);
}
}
This program should accept the string XYZ and prints Your string is XYZ
You need to read the output (and error) streams from the Process using getInputStream() and getErrorStream(). You’ll need a separate thread for this if you want to wait for the process to complete.
String[] cmd = {"java", "-cp", "C:/Users/..../workspace/Testing/bin", s, str};
Process p = new ProcessBuilder(cmd).redirectErrorStream(true).start();
final InputStream pOut = p.getInputStream();
Thread outputDrainer = new Thread()
{
public void run()
{
try
{
int c;
do
{
c = pOut.read();
if (c >= 0)
System.out.print((char)c);
}
while (c >= 0);
}
catch (IOException e)
{
e.printStackTrace();
}
}
};
outputDrainer.start();
p.waitFor();
If you are using Java 7 and want all output of the process to be redirected to the console, the code is considerably simpler:
String[] cmd = {"java", "-cp", "C:/Users/..../workspace/Testing/bin", s, str};
Process p = new ProcessBuilder(cmd).redirectError(Redirect.INHERIT)
.redirectOutput(Redirect.INHERIT)
.start();
p.waitFor();
The redirectError() and redirectOutput() methods with Redirect.INHERIT cause output to just be sent to the parent Java process.
You are executing javac, the language compiler. I believe you want to invoke the java runtime on the class file with your main method. Replace javac with java, and specify your main class.
You are passing your data as an Argument but reading it from System.in. If you read the data from the arguments it'll work. So do what #prunge said to capture what the subprocess print and use this as your test and everything will work just fine.
import java.io.*;
public class Test
{
public static void main(String[] args) throws IOException
{
if(args.length==0)
System.out.println("No String received");
else
System.out.println("Your string is " + args[0]);
}
}
Be sure that you check both the InputStream and the ErrorStream.
If you however want to pass the data via System.in then you have to change your call code to:
InputStreamReader isr=new InputStreamReader(System.in);
BufferedReader br=new BufferedReader(isr);
System.out.println("Enter the class name");
String s=br.readLine();
String str="XYZ";
String[] cmd = {"java","-cp", "C:/Users/..../workspace/Testing/bin",s};
Process pro=Runtime.getRuntime().exec(cmd);
PrintWriter output= new PrintWriter(pro.getOutputStream());
output.println(str);

Java thread question

Im trying to implement a scenario using threads to execute concurrent commands on a server. The commands just send requests to a service running on the server and in return get the required output.
The commands are generated based on reading a file, whose path the user gives as input to the application.
Based every line that is in the aforementioned file, a command is generated and run on the server.
Im running these commands by invoking an instance of the bash process on the linux box.
A brief pseudo implementation of the above is as follows.
Class A {
public static void main(blah blah)
//take all user inputs, one of which is the location of the file that is to be read.
try {
Runnable runnable =new bckwork(//pass the inputs taken from the user//);
thread = new Thread(runnable);
thread.start();
}
catch (Exception e) {
e.printStackTrace();
}
}
and the class that does the actual work --
public class bckwork implements Runnable {
bckwork(//takes in all input that the other class passes on) {
//assigns to local variables
}
public void run() {
// TODO Auto-generated method stub
try{
Process proc = null;
proc = Runtime.getRuntime().exec("/bin/bash", null, dir);
if (proc != null) {
String cmd="";
BufferedReader in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(proc.getOutputStream())), true);
BufferedReader br = new BufferedReader(blah blah blah);//reads every line in the file that was passed onto this class.
String strLine;
while ((strLine = br.readLine()) != null) {
cmd=blah+blah+blah//the command is generated,whatever is read off the file is a part of the command.
out.println(cmd);
String line;
while ((line = in.readLine()).length()>1) {
line = in.readLine();
System.out.println(line);
proc.waitFor();
in.close();
out.close();
proc.destroy();
}
}
}
}catch(Exception e){}
}
}
The problem with the above pieces of code is that they run only for the first line in the file that is being read and then the executions goes into some kind of deadlock. Im guessing that the next line from the file is never being read.My intention was to kick of a thread for every line that was being read or essentially every command that was being constructed.
Any pointers on how this bug can be corrected would be greatly appreciated.
In
while ((line = in.readLine()).length()>1)
in.readLine waits for enter and freezes the entire application.

Categories

Resources