15

I am working on a simple java program. It simply compiles and executes another java program. I am using Runtime.exec() function to compile and run. There is no problem with compilation. but when it runs, if the second program needs an input to read from keyboard, I can't give it from the master process. I used getOutputStream() function. but it couldn't help. I will provide my code.

public class sam {  
    public static void main(String[] args) throws Exception {  
        try { 
             Process p = Runtime.getRuntime().exec("javac sam2.java");
             Process p2 = Runtime.getRuntime().exec("java sam2");
             BufferedReader in = new BufferedReader(  
                                new InputStreamReader(p2.getInputStream()));

             OutputStream out = p.getOutputStream();
             String line = null; 
             line = in.readLine();
             System.out.println(line);
             input=input+"\n";
             out.write(input.getBytes());
             p.wait(10000);
             out.flush();
        }catch (IOException e) {  
             e.printStackTrace();  
        }  
    }  
}  

This is my master program(sam.java).

The following is the code of sam2.java

public class sam2 {  
public static void main(String[] args) throws Exception {  

    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    String str; 
    System.out.println("Enter the number..\n");
    str = br.readLine(); 
    System.out.println(Integer.parseInt(str));

    }  
}  

There is no problem, if my second program has only printing statements. But the problem arises when I have to read something from the other.

Ajoy
  • 1,838
  • 3
  • 30
  • 57
AKA
  • 5,479
  • 4
  • 22
  • 36

5 Answers5

21

It is a bit strange but you can run the second program without forking it. Just calling the main method in it. So forget the runtime section and do this:

sam2.main(new String[0]);

Of course this way you must compile sam2 at compile time

András Tóth
  • 605
  • 4
  • 12
  • i couldnt understand what u mean by this statement..!! :( – AKA Mar 05 '13 at 12:32
  • 1
    It works.. :) thanks a lot.. But when i use this way.. the entire control will be gone to the second program. so master will execute only after the completion of the second program.. should i use threads to solve this problem..?? – AKA Mar 05 '13 at 12:49
  • Problem..!!! when i store the class name of second program to a string variable it encounters the following error.. **cannot find symbol tempfile.main(new String[0]);** **symbol: method main(String[])** **location: variable tempfile of type String** What should i do..?? – AKA Mar 06 '13 at 04:47
  • What do you want? You can not use a String as a class instance. Maybe you should use java reflection to this work. But reflection is usually not needed. – András Tóth Mar 07 '13 at 10:01
14

Each process needs to be allowed to run and finish. You can use Process#waitFor for this purpose. Equally, you need to consume any output from the process at the same time. waitFor will block so you will need use a Thread to read the input (and if you need to, write output to the process)

Depending on the location of the java/class file, you may also need to specify a starting folder from which the execution of the process can start.

Most of this significantly easier using ProcessBuilder

import java.io.File;
import java.io.IOException;
import java.io.InputStream;

public class CompileAndRun {

    public static void main(String[] args) {
        new CompileAndRun();
    }

    public CompileAndRun() {
        try {
            int result = compile("compileandrun/HelloWorld.java");
            System.out.println("javac returned " + result);
            result = run("compileandrun.HelloWorld");
        } catch (IOException | InterruptedException ex) {
            ex.printStackTrace();
        }
    }

    public int run(String clazz) throws IOException, InterruptedException {        
        ProcessBuilder pb = new ProcessBuilder("java", clazz);
        pb.redirectError();
        pb.directory(new File("src"));
        Process p = pb.start();
        InputStreamConsumer consumer = new InputStreamConsumer(p.getInputStream());
        consumer.start();

        int result = p.waitFor();

        consumer.join();

        System.out.println(consumer.getOutput());

        return result;
    }

    public int compile(String file) throws IOException, InterruptedException {        
        ProcessBuilder pb = new ProcessBuilder("javac", file);
        pb.redirectError();
        pb.directory(new File("src"));
        Process p = pb.start();
        InputStreamConsumer consumer = new InputStreamConsumer(p.getInputStream());
        consumer.start();

        int result = p.waitFor();

        consumer.join();

        System.out.println(consumer.getOutput());

        return result;        
    }

    public class InputStreamConsumer extends Thread {

        private InputStream is;
        private IOException exp;
        private StringBuilder output;

        public InputStreamConsumer(InputStream is) {
            this.is = is;
        }

        @Override
        public void run() {
            int in = -1;
            output = new StringBuilder(64);
            try {
                while ((in = is.read()) != -1) {
                    output.append((char) in);
                }
            } catch (IOException ex) {
                ex.printStackTrace();
                exp = ex;
            }
        }

        public StringBuilder getOutput() {
            return output;
        }

        public IOException getException() {
            return exp;
        }
    }
}

Now obviously, you should check the return results of the processes, and may be produce a better mechanism for interacting with the processes, but that's the basic idea...

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
1

You can just call the main method of the second class. The main method is just like any other static method.

Jay Q.
  • 4,979
  • 3
  • 33
  • 36
0

This is what worked for me:

try {
    single.main(new String[0]);
} catch (Exception e) {
    JOptionPane.showMessageDialog(null, e);
}
Stephen Rauch
  • 47,830
  • 31
  • 106
  • 135
denis
  • 1
0

Just call the main class file. For example, if your java class file name is xyz.java, you can call and execute the same in java swing application on click of a JButton, code is

private void Btn_createdatabaseActionPerformed(java.awt.event.ActionEvent evt) {                                                   
       xyz.main(new String[0]);
}

That's it...

Malakai
  • 3,011
  • 9
  • 35
  • 49