2

I'm trying to create an autograder for my Java programming class I'm teaching this semester. The basic idea of the autograder is that it will place a copy of my tester's .class file in same location as the students' turnins (each in their own folder). It will report the results in a text file and give the data back to me.

The issue that I'm stuck on is that I cannot get the ProcessBuilder to execute my tester class, and I've tried various different ways of typing the command out, but I'm not sure what the correct command is. Here is the code:

public...main(String[] args){
///Code not relevant ommitted
    Runtime runtime = Runtime.getRuntime();

    for (String person : uniqueIds) {
        File currentLoc = new File(HW_ID + "/" + person);
        ProcessBuilder g = new ProcessBuilder("bash", "-c",
                "java", " -cp ", currentLoc.getAbsolutePath(),
                " Grader");
        Process process = g.start();
        process.waitFor();
    }
}

"uniqueIds" is a String Array that contains each student's uniqueId, which is the name of the folder that their homework is turned in to. "HW_ID" is a constant that is the name of the folder that the turnin set for all of the students is housed in. So the file structure is: HW_ID/uniqueID/

"Grader" is the name of my program that will grade the turnins. How can I use ProcessBuilder to start my Grader program that is in the specified file location?

EDIT: I'm using a Mac on this, but if the code for Windows is different, please list both. Thanks!

  • What errors did you get? – A4L Jan 21 '14 at 22:06
  • Your fifth line is not needed and redundant. Get rid of currentLoc = new File(currentLoc.getAbsolutePath()); To run your java program using ProcessBuilder try something like: ProcessBuilder("java.exe","-cp",currentLoc.getAbsolutePath()). – Alan Jan 21 '14 at 22:29
  • @A4L no errors reported. The code runs, but the text files that should be created from the execution of Grader are not present, which indicates that the call to Grader did not go through correctly. – db4soundman Jan 21 '14 at 22:34
  • the method [Process#waitFor()](http://docs.oracle.com/javase/7/docs/api/java/lang/Process.html#waitFor()) returns an int, which is the exist status of commad executed, please evaluate it. Also consider Eric's answer, [ProcessBuilder](http://docs.oracle.com/javase/7/docs/api/java/lang/ProcessBuilder.html) takes an array or a list where each element is a single argument, If multiple arguments are manually concatenated, they will be passed as a single argument. – A4L Jan 21 '14 at 22:40
  • I've read things about people using Input Streams and Buffered Readers...do I need to consider that even though the Grader program only outputs text files? – db4soundman Jan 21 '14 at 22:49

2 Answers2

2

You need to separate the process arguments with a comma rather than using +. Otherwise it concats them to be a single parameter "java-cp"...

... g = new ProcessBuilder("bash", "-c", "java", "-cp", ...

Eric Woodruff
  • 6,380
  • 3
  • 36
  • 33
  • So the portion from "currentLoc.toString() ..... person" should still have + signs because that is the filepath to the program that needs to run, correct? – db4soundman Jan 21 '14 at 22:37
  • To be honest your -cp doesn't look much like a directory containing java classes or a jar to me, so it is hard to say. But you should really pass the path parameters to the File object itself and use currentLoc.getPath() or something like getAbsolutePath() as your cp parameter (that can also help you with any platform specific issues in the path). Therefore I suggest moving the File to within the for loop. – Eric Woodruff Jan 21 '14 at 22:53
  • Edited the code to reflect that suggestion. Still doesn't seem to be working. Is there a chance I need to use InputStreams and BufferedReaders even though I don't have any console output, only text files? – db4soundman Jan 21 '14 at 23:05
  • No input streams needed here. – Eric Woodruff Jan 21 '14 at 23:07
  • The spaces in " -cp " could be an issue when I try 'java " -cp " .' in a shell I get a different output than 'java -cp .' – Eric Woodruff Jan 21 '14 at 23:10
  • Just played around with the spaces and that didn't get the second program to run. – db4soundman Jan 21 '14 at 23:20
  • Ok, while not required, capturing stdout and stderr streams and printing them would help you debug it. You should really do that in a background thread while the main thread calls waitFor. – Eric Woodruff Jan 21 '14 at 23:25
0

Assuming the program you are trying to run is a Java program and that it exists in the same current directory, here is an example of how I can run a program named SerialNumber.java from another program named Tester.java.

SerialNumber.java:

import java.io.*;

public class SerialNumber
{
  public static void main(String[] args)
  {
    try{
      SerialNumber sn = new SerialNumber();
      System.out.println(sn.executeVolCommand());
    }
    catch(Exception e){e.printStackTrace();} 
  }

  public String executeVolCommand()
  {
    String NEWLINE = System.getProperty("line.separator");
    StringBuffer buffer = new StringBuffer();
    try{

      Process pb = new ProcessBuilder("cmd","/c", "vol").start();  
      InputStream in = pb.getInputStream();  
      BufferedReader br = new BufferedReader(new InputStreamReader(in));  
      String line;  
      while ((line = br.readLine()) != null) {  
        buffer.append(line + NEWLINE);  
      }
    }
    catch(Exception e){e.printStackTrace();}
    return buffer.toString(); 
  }
}

Tester.java:

import java.io.*;

public class Tester
{
  public static void main(String[] args)
  {
    try{
      File currentLoc = new File("SerialNumber");
      System.out.println(currentLoc.getAbsolutePath());
      ProcessBuilder pb = new ProcessBuilder("java.exe",currentLoc.getName());
      Process p = pb.start();

      //Read out dir output
      InputStream is = p.getInputStream();
      InputStreamReader isr = new InputStreamReader(is);
      BufferedReader br = new BufferedReader(isr);
      String line;

      while ((line = br.readLine()) != null) {
        System.out.println(line);
      }
    }
    catch(Exception e){e.printStackTrace();}
  }
}

Hope this helps.

Alan
  • 822
  • 1
  • 16
  • 39
  • To compare my situation to this example, the SerialNumber.java file (my Grader) sits two folder levels further in the directory than where you would be running Tester.java from. – db4soundman Jan 21 '14 at 23:11
  • Determine where the program is and set it when you declare your File object: File currentLoc = new File("folder1" + File.separator + "folder2" + File.separator + "SerialNumber"); In your case, you might want to replace the String literals folder1 and folder2 with values coming in from the command line: File currentLoc = new File(args[0] + File.separator + args[1] + File.separator + "SerialNumber"); – Alan Jan 22 '14 at 00:38