Over a million developers have joined DZone.

Calling a Native Program from within Java

· Java Zone

Discover how powerful static code analysis and ergonomic design make development not only productive but also an enjoyable experience, brought to you in partnership with JetBrains

It had been a long time since I had a need to call a system process from inside Java. The last time I needed to do this, I used Runtime.exec(). Now there is a new sheriff in town… ProcessBuilder. ProcessBuilder was introduced in JDK 5 and makes it super simple to call native processes.

I had two separate cases that I needed to solve. One was a call to a C program with a parameter that returned one line of objects that I needed to parse. The other was a call to a C and it returned multiple lines to me. I only cared about some of the lines of output from the program.

Here is the first example. It calls a C program with one parameter and parses the single line of output. I can call the C program from the command line via:

/usr/local/bin/randint32  5

The output is similar to:

2048211571,-446295626,-1826753911,773673606,-163405466,

Here is the Java method that I used to call the C program and parse the data:

  • Line 11 – 12 – The ProcessBuilder is instantiated with the command as the first parameter and the parameter to the command as the second parameter.
  • Line 13 – This is where the process is returned from calling start()on the ProcessBuilder object.
  • Line 15 – The input stream is retrieved from the process object.

Beyond the Process/ProcessBuilder processing is normal Java code. The process returns me one line, which contains comma-separated integers. I split the string into a bunch of strings containing integer data. I convert them to integers and add them to the Queue. I also set a couple of flags that are related to the application, but are beyond the scope of this article.

/**
 * Fills the integer queue with integers.  Opens the process that calls the USB device, reads the data, splits the
 * CSV into integers and adds them to the queue.  Sets the RNG device to available as it writes integers to the
 * queue.
 * @throws InterruptedException throws if the put operation is interrupted by a timeout
 */
public void getRandomIntegerData() throws IOException, InterruptedException {
    int integersToGenerate = DESIRED_QUEUE_LENGTH - integerQueue.size();
    try {
        logger.info("Retrieving {} integers from Comscire by calling randint32...", integersToGenerate);
        ProcessBuilder processBuilder = new ProcessBuilder("/usr/local/bin/randint32",
                                                           Integer.toString(integersToGenerate));
        Process process = processBuilder.start();
 
        BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()));
        String data = br.readLine();
        for (String stringInt : data.split(",")) {
            integerQueue.put(Integer.valueOf(stringInt));
            // check it to ensure that it hasn't been emptied as fast as it could be filled
            if (integerQueue.size() > 0) {
                setAvailable(true);
                setErrors(false);
            }
        }
    } catch (IOException e) {
        setErrors(true);
        logger.error("Unable to get integers from Comscire process", e);
        throw e;
    }
}

The next C program that I had to call returned diagnostic information from a Comscire hardware random number generator. The command that I used to retrieve the data is:

/usr/local/bin/diagnostics

The data is returned as a series of lines containing the following data. I was only concerned with two of the lines from the output:

  • Status: QNG device reports success.
  • DeviceID QWR40026
Start Device...
 
Status: QNG device reports success.
 
DeviceID QWR40026
 
 
Get 128 Raw Bytes - Level 2, Stream 3 (hex)
 
76 6D 02 B6 BC 05 1D B1 7C 92 BC D7 69 2D 86 27 CC 5D EE 16 4F 17 97 EA B9 BA 32 AE E4 FC FA 57 4B 9C 74 48 0C 51 79 5B 47 82 3C 4B 66 EE 5A EA 83 C2 12 10 AF F2 8F 7B E2 D0 CD 84 40 96 94 A3 30 2D C3 AD 7F FD 06 9C 1F 2A 20 26 41 73 B9 EA 4B 82 DE AB 31 D8 FA 5D 20 1E EA 0F F2 D6 5A BB 4A 82 67 70 C4 C8 40 6E CA 7B 84 DA B4 3D 99 0A A6 BC 36 C3 94 D9 84 D9 F9 5B 00 95 01 4C 64 E2
 
EXIT...
  • Line 9 – The ProcessBuilder is instantiated with the command.
  • Line 10 – The process is assigned from callingprocessBuilder.start().
  • Line 12 – The input stream is retrieved from the process object.

I loop over the individual lines of data looking for the 2 lines of data that I need to retrieve. I add those to a StringBuilder. Just for efficiency’s sake, I look for a line that tells me that I am done. There is no data that I am concerned with after this line.

/**
 * Retrieves the diagnostic information from the Comscire device.
 * @return String containing the "Status" and "DeviceID" information
 * @throws IOException
 */
public String getDiagnostics() throws IOException {
    StringBuilder output = new StringBuilder();
    try {
        ProcessBuilder processBuilder = new ProcessBuilder("/usr/local/bin/diagnostics");
        Process process = processBuilder.start();
 
        BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()));
        String data = null;
        boolean done = false;
        while ((data = br.readLine()) != null && !done) {
            if (StringUtils.startsWith(data, "Status") ||
                StringUtils.startsWith(data, "DeviceID")) {
                output.append("\t").append(data).append("\n");
            } else if (StringUtils.startsWith(data, "Get 128 Raw Bytes")) {
                done = true;
            }
        }
    } catch (IOException e) {
        setErrors(true);
        logger.error("Unable to get diagnostics from Comscire process", e);
        throw e;
    }
 
    return output.toString();
}
There you have it. Two examples showing how easy it is to useProcessBuilder to execute native processes from a Java application.




















Learn more about Kotlin, a new programming language designed to solve problems that software developers face every day brought to you in partnership with JetBrains.

Topics:

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
Subscribe

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}