Using a ProcessBuilder to Execute an OS Level Command and Properly Read the Exit Code from a Java Process

There are many a situation where a developer will want to execute an OS level command in another process and read not only the standard out (stdout), and standard error (sterr), but also the exit code returned from the process.

To do so, utilize the ProcessBuilder class along with a helper class (ProcessWrapper) that will provide the ability to set a timeout for the process and read the exit code in a separate thread.

Following is an example and the ProcessWrapper class with an explaination:

import java.io.IOException;

public class ProcessBuilderTest {

    /**
     * Time in milliseconds that we will wait for the process to complete before
     * timing out and killing it.
     */
    private static final long fTimeout = 10000;

    public static void main(String[] args) {

        String[] commandArray = { “some”, “command” };

        ProcessBuilder processBuilder = new ProcessBuilder(commandArray);

        Process process = null;
        try {
            process = processBuilder.start();
        } catch (IOException e) {
            // TODO: Error handling, logging
        }

        // ——————————————————————–
        // Read the exit code from the fProcess
        ProcessWrapper processWrapper = new ProcessWrapper(process);
        processWrapper.start();

        int exitCode = 0;
        try {
            processWrapper.join(fTimeout);

            // Check for an exit code from the process
            if (processWrapper.getfExitCode() != null) {
                exitCode = processWrapper.getfExitCode();
            } else {
                // Set our exit code to 1
                exitCode = 1;
                process.destroy();
            }
        } catch (InterruptedException e) {
            processWrapper.interrupt();
            Thread.currentThread().interrupt();
            process.destroy();
        }

        System.out.print(“exitCode = ” + exitCode);
    }

    public static class ProcessWrapper extends Thread {

        private final Process fProcess;

        private Integer fExitCode;

        public Integer getfExitCode() {
            return fExitCode;
        }

        public ProcessWrapper(Process fProcess) {
            this.fProcess = fProcess;
        }

        public void run() {
            try {
                fExitCode = fProcess.waitFor();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

In the ProcessBuilderTest main() method the command to be executed is build in the commandArray String[].

A ProcessBuilder instance is created and passed the command to execute. Then a Process instance providing a reference to the process running on the OS is instantiated via the ProcessBuilder.start() command.

Here is where the wrapper class that helps us to read the exit code comes in. A ProcessWrapper is instantiated and passed a reference to the process on construction, and then the thread started with the .start() invocation.

Then processWrapper.join(fTimeout) is invoked telling the current thread to wait for the completion of the processWrapper thread, or interrupt it (timeout) after the value of fTimeout (in this case 10 seconds).

If the processWrapper thread completes before the timeout the main thread invokes processWrapper.getfExitCode(), to acquire the exit code from the process. If not, the process is killed and we pass an exitCode of 1 to indicate abnormal completion.

Attached is a .zip of the java classes for reference and testing.

Dynamically Instantiating Classes in Java

Edited 2021-02-08 to reflect API changes for Java 11.

There are a number of cases when you may not know exactly what class you will be instantiating and want to be able to dynamically instantiate specific classes based on a configuration file or a condition during runtime.

To do so, you will need to define a parent class, abstract class, or interface for your classes and can then use the following code as a guide.

Given the following class definitions:

An abstract class

package com.ryanchapin.examples;

public abstract class MyAbstractClass {

    protected int x;
    protected int y;

    public void setX(int x) {
        this.x = x;
    }

    public void setY(int y) {
        this.y = y;
    }

    public MyAbstractClass() {}

    public MyAbstractClass(Integer x, Integer y) {
        this.x = x;
        this.y = y;
    }

    public abstract int doSomething();
}

Two concrete implementations

package com.ryanchapin.examples;

public class MyMultiplyingClass extends MyAbstractClass {

    public MyMultiplyingClass() {}

    public MyMultiplyingClass(Integer x, Integer y) {
        super(x, y);
    }

    @Override
    public int doSomething() {
        return x * y;
    }
}
package com.ryanchapin.examples;

public class MyAddingClass extends MyAbstractClass {

    public MyAddingClass() {}

    public MyAddingClass(Integer x, Integer y) {
        super(x, y);
    }

    @Override
    public int doSomething() {
        return x + y;
    }
}

A Main class in which we can run the example

package com.ryanchapin.examples;

public class Main {

    public static void main(String[] args) {
        String myMultiplyingClass = "com.ryanchapin.examples.MyMultiplyingClass";
        String myAddingClass = "com.ryanchapin.examples.MyAddingClass";

        /*
         * Instantiating the class via the no-arg constructor and then using the
         * setters to "configure" the instance.
         */
        MyAbstractClass noArgConstructorInstance = null;
        try {
            @SuppressWarnings("unchecked")
            Class<MyAbstractClass> instanceClass =
                (Class<MyAbstractClass>) Class.forName(myMultiplyingClass);
            noArgConstructorInstance = instanceClass
                .getDeclaredConstructor()
                .newInstance();
        } catch(Exception e) {
            e.printStackTrace();
        }
        noArgConstructorInstance.setX(5);
        noArgConstructorInstance.setY(2);
        System.out.println(noArgConstructorInstance.doSomething());

        /*
         * Instantiating the class via the constructor that takes the x and y
         * parameter values.
         */
        MyAbstractClass xyArgConstructorInstance = null;
        try {
            @SuppressWarnings("unchecked")
            Class<MyAbstractClass> instanceClass =
                (Class<MyAbstractClass>) Class.forName(myAddingClass);
            /*
             * Specify the signature of the constructor that we want to invoke
             * by passing in the types defined in the target constructor.  Then,
             * pass in the arguments to the constructor with the newInstance
             * method.
             */
            xyArgConstructorInstance = instanceClass
                .getDeclaredConstructor(Integer.class, Integer.class)
                .newInstance(5, 2);
        } catch(Exception e) {
            e.printStackTrace();
        }
        System.out.println(xyArgConstructorInstance.doSomething());
    }
}

The Main class illustrates two different ways that we can instantiate our class. One, using the no-arg constructor, and another, by using reflection to get a reference to the constructor with the defined arguments.

The Main class assumes that it will be called with the fully qualified class name as the first argument and will use that String to attempt to instantiate a concrete instance of the MyAbstractClass. The abstract class can be either an interface, or a concrete parent class.

Preserving File Permissions When Copying Files with Ant

If you want to retain the file permissions of a file that you copy with ant you must use the <exec> command instead of? <copy>.

So, instead of:

<copy file=”${source.file}” tofile=”${dest.path}/${dest.file}” overwrite=”true”/>

Use:

<exec executable=”cp”>
? <arg value=”-pf”/>
? <arg value=”${source.file}”/>
? <arg value=”${dest.path}/${dest.file}”/>
</exec>

java.lang.OutOfMemoryError: unable to create new native thread Exception When Using SmbFileInputStream

I am writing an application that copies files from a Samba share using the JCIFC Java CIFS Client Library (which, btw, is a very helpful, widely used, and well developed project).

As usual I am under the gun to get something up and running so I do not have the luxury to explore all of the details as much as I would like. My application gets a directory listing of a Samba share and then spawns a new thread for each new file (with a limit, of course) which copies the file to the local file system via a SmbFileInputStream and FileOutputStream as follows (without the obligatory try/catch blocks for readability):

(An SmbFile instance is provided by the calling code)

byte[] readBuffer = new byte[1024];
int bytesRead = 0;

File fileDestination = new File(“/tmp/”, “destinationFile”);
FileOutputStream fileDestinationFOS = new FileOuputStream(fileDestination);

SmbFileInputStream smbFIS = new SmbFileInputStream(smbFile);

while ((bytesRead = smbFIS.read(readBuffer)) != -1 ) {
fileDestination.write(readBuffer, 0, bytesRead);
}

smbFIS.close();
fileDestinationFOS.close();

When I run it I get the following Exception:

Exception in thread “Thread-3” java.lang.OutOfMemoryError: unable to create new native thread
at java.lang.Thread.start0(Native Method)
at java.lang.Thread.start(Thread.java:614)
at jcifs.UniAddress.lookupServerOrWorkgroup(UniAddress.java:173)
at jcifs.UniAddress.getAllByName(UniAddress.java:290)
at jcifs.UniAddress.getByName(UniAddress.java:245)
at jcifs.smb.Dfs.getTrustedDomains(Dfs.java:62)
at jcifs.smb.Dfs.resolve(Dfs.java:167)
at jcifs.smb.SmbFile.resolveDfs(SmbFile.java:671)
at jcifs.smb.SmbFile.send(SmbFile.java:773)
at jcifs.smb.SmbFileInputStream.readDirect(SmbFileInputStream.java:181)
at jcifs.smb.SmbFileInputStream.read(SmbFileInputStream.java:142)
at jcifs.smb.SmbFileInputStream.read(SmbFileInputStream.java:132)
at com.ngc.amap.mapDaemon.FileScanDaemon$RemoteFileCopier.run(FileScanDaemon.java:461)
at java.lang.Thread.run(Thread.java:636)

After considerable searching and testing I determined that the call to jcifs.smb.SmbFile.resolveDfs(SmbFile.java:671) was spawning numerous Threads that were consuming all of the RAM availble to naitive thread in my JVM. Increasing the amount of RAM to the JVM didn’t help.

The solution that I found was to set the following properties in my application prior to the instantiation of any of the jcifs.* classes. In this case, these properties were set in the main method of my entry point class.

System.setProperty(“jcifs.resolveOrder”, “DNS”);
System.setProperty(“jcifs.smb.client.dfs.disabled”, “true”);

Once set, I was able to run as expected without the OutOfMemoryErrors

Adding a ShutdownHook to a Java Program to Enable Clean Exit on CTRL-C

Often times I will be building a Java program that will either be run from a command-line or as a system service.  In most cases, during development, I’ll be running it directly from the command-line and will want to kill it by pressing control c on the keyboard.

When I do that I want to make sure that my program cleanly exits, closing any open files, socket connections, database connects, or what have you.

To do so, you must invoke the addShutdownHook(Thread) method on the Runtime.getRuntime() instance for a given process.

Following is a quick how-to on setting that up.

You need the following 4 things:

  1. The class that you want to be able to shutdown cleanly, we will call this the Parent.
  2. A class that extends Thread, we will call this the ShutdownThread class.  This class will call a method in the Parent
  3. An interface that the Parent will implement, called the ShutdownInterface.
  4. The invocation of the Runtime.getRuntime().addShutdownHook(ShutdownInstance) in the Parent.

The classes:

/** ***************************************************
 *
 * The ShutdownInterface
 */


public interface IShutdownThreadParent {
    public void shutdown();
}


/** ***************************************************
 *
 * The ShutdownThread
 */


public class ShutdownThread extends Thread {

    private IShutdownThreadParent mShutdownThreadParent;

    public ShutdownThread(IShutdownThreadParent mShutdownThreadParent) {
        this.mShutdownThreadParent = mShutdownThreadParent;
    }

    @Override
    public void run() {
        this.mShutdownThreadParent.shutdown();
    }
}

 /** ***************************************************
 *
 * The Parent
 */

public class Parent implements IShutdownThreadParent{

    private  ShutdownThread fShutdownThread;

    public Parent() {
        // Instantiate a new ShutdownThread instance and invoke the addShutdownHook method.
        fShutdownThread = new ShutdownThread(this);
        Runtime.getRuntime().addShutdownHook(fShutdownThread);
    }

    @Override
    public void shutdown() {
        // code to cleanly shutdown your Parent instance.
    }

    public static void main(String[] args) {
        Parent parent = new Parent();
    }
}

When instantiated the Parent class instantiates a new ShutdownThread instance, passing it a reference to itself.  The Parent class then invokes the addShutdownHook() method passing it the reference to the ShudownThread instance.

When CTRL-C is pressed on the keyboard, the JVM will invoke the run method in the ShutdownThread class which will then invoke the shutdown() method in the parent class enabling you to cleanly exit before the JVM exits.

Replacing Smart Quotes (<91> and <92>) in vi

Smart quotes will be displayed as <91> and <92> in vi. A number of other special characters will also be displayed in similar fashion <96>, etc. . . .

To replaced them use do the following:

  1. Type:? ‘:’ 1,%s/
  2. Then, since it is a special character, you can’t simply type ‘<91>’ or that string will not be matched, so:
  1. Press: CTRL and V
  2. Then type: [space] x [space] 91
  3. [Enter]

Configuring CentOS to run SELinux in Strict Mode

I am in the process of setting up some CentOS/RHEL 6 servers to run SELinux in strict mode. What follows are notes, links to online resources and things that I am discovering along the way. Once I am finished I will go back and re-write it to follow more of a how-to/guide type format. In the meantime, it might seem a bit disjointed.

Links/Resources:

  • http://wiki.centos.org/HowTos/SELinux
  • http://fedoraproject.org/wiki/SELinux
  • http://www.centos.org/docs/5/html/Deployment_Guide-en-US/rhlcommon-chapter-0001.html
  • http://www.nsa.gov/research/selinux/index.shtml

MaintLog Notes:

  • Make sure that the selinux-policy-strict package (and deps) are installed:
  • # yum install selinux-policy-strict
  • After installing the policy I was unable to reboot as I hadn’t relabeled the file system properly. If having problems booting try:
  • # genhomedircon
  • # touch /.autorelabel
  • # reboot
  • After successfully booting with strict mode enabled you will not be able to do the things that you would normally expect as a root user.This is because your root shell does not have access to the system administrator role. To do so invoke the newrole command:
  • # newrole -r sysadmin_r
  • LEFTOFF: it seems semanage isn’t installed. I’ll need to restart with selinux disabled to install it so that I can sort out running newrole properly:? see: http://www.spinics.net/lists/selinux/msg09681.html
  • Make sure that the semanage package is installed: # yum install libsemanage