Wrapper Native Execute Overview

Overview

The WrapperManager.exec() function is an alternative to Java-Runtime.exec() or Java-ProcessBuilder that has the disadvantage to use the fork() method, which can become on some platforms very memory expensive to create a new process. The problem on those platforms is that in the Parent Process that wants to start a side process, fork() causes to clone the memory heap of the parent for the child. This will double the used memory for a short time. Given a fairly large application that is close to the system's memory quota, it might fail to just create a small application like ls, or the memory is going to get swapped on the HD, which decreases the performance drastically.

Another issue is to ease bind or detach the child while starting from the parent. If the Java Process terminates expectedly or unexpectedly, the Wrapper will clean all bind processes that haven't finished yet.

For better consistency, the WrapperManager.exec() function was implemented as close to the Runtime.exec() function in Java as possible.

Executing

Start

This section will start right away to show how to execute a command. (Further details will be explained step-by-step during reading this page)

WrapperProcess p = WrapperManager.exec("ls -lisa");

The above line will execute a ls command with the parameters -l, -i, -s, and -a, and then assign a WrapperProcess object representing the process.

If the full path of the binary (or script) file hasn't been passed, the current working directory as well as systems' PATH directories will be checked and the first found hit gets executed. Relative addressing starting from the current working directory is also supported.

NOTE

The exec command accepts the command either as a single String as well as a StringArray. In case of a StringArray, each parameter is located in a single array field.

Process I/O

The created child process runs in the background of the OS and is usually not visible, as long as it's not a GUI application. To communicate with the process, the WrapperProcess class provides three methods to access the Input to the process as well as the Output and the ErrorMessages to the process.

It is recommended to wrap the returned StreamObject with a BufferedReader. To open the Reader, please proceed as described.

BufferedReader br = new BufferedReader( new InputStreamReader(p.getWrapperProcessInputStream()));

This establishes the Reader of the InputStream on which the child writes its output. To read data from the ErrorStream or write data to the Child, please proceed similar to this example.

Once the Reader/Writer has been established, we can read/write data by:

String line;
while ((line = br.readLine()) != null)
{
    System.out.println(line);
}
br.close();

NOTE

Please note that by following this example, all data will be read until the child process closes the stream on its side.

Configuration of the Child Process

When executing a command, WrapperManager also provides the possibility to configure the child process. This is done by passing a WrapperProcessConfig object to the exec() function. The following section will explain the Configurations that can be made by WrapperProcessConfiguration.

Detached Process

The setDetached() method lets you specify whether the subprocess will be run "detached" from the Wrapper. If the process is marked as "detached", the process doesn't need to terminate when the Wrapper is shutting down. If not marked, the Wrapper will keep track of the child process and try to terminate the process if the parent process should terminate.

NOTE

By default, processes won't be started detached from its parent process.

Start Type

The setStartType() method specifies a Start Type of how the subprocess will be started by the OS.

WARNING

This property has no effect on Windows.

  • FORK_EXEC:

    This is the most common way in Linux/UNIX to create a child process. However, on some OS (esp. Solaris), this call causes to initially duplicate the memory of the parent for the child. On z/OS, this Start Type is not supported as of the initial release. On HP-UX systems, the Wrapper will automatically switch to using vfork() rather than fork().

  • VFORK_EXEC:

    The vfork() function differs from fork() only when the child process can share code and data with the parent process. This speeds cloning activity significantly at a risk for the integrity of the parent process if vfork() is misused. On some systems, vfork is the same as fork. On z/OS, this Start Type is not supported as of the initial release.

  • POSIX_SPAWN:

    Process will be spawned and won't cause any memory duplication POSIX_SPAWN API. This is only available on Linux, Solaris (10+), AIX, z/OS, MacOS, and FreeBSD 8+ (Since version 3.5.46).

  • DYNAMIC:

    The optimal Start Type will be automatically selected according to the OS the Wrapper is running on. Please note that this property also implies that changing the working directory will not be supported because of not supporting changing the working directory when using POSIX_SPAWN. There is an experimental property wrapper.child.allowCWDOnSpawn that could be used to achieve in changing the working directory.

NOTE

By default, processes will be launched using the Start Type DYNAMIC.

Working Directory

The setWorkingDirectory() method specifies the working directory of the subprocess, or "NULL" if the subprocess should inherit the working directory of the current process.

Please note that it is not possible to set the working directory directly when using POSIX_SPAWN. A suggested workaround would be to wrap the command you wish to run in a script and perform a change of directory prior to the execution of the command.

#!/bin/sh

chdir $1
shift
$*

NOTE

If this property is not set, the subprocess will inherit the working directory from its parent process.

wrapper.child.allowCWDOnSpawn

The wrapper.child.allowCWDOnSpawn property controls whether the Wrapper will try to change the working directory for the Start Types POSIX_SPAWN and DYNAMIC.

This property is experimental and could lead to problems if the wrapped process is using Java Native Interface (JNI) Code and would try to create a child process using POSIX_SPAWN.

By default, this property is set to FALSE.

wrapper.child.allowCWDOnSpawn=TRUE

Setting the Environment

The setEnvironment() method specifies the environment of the created subprocess.

The field is an array of strings. Each element of it has environment variable settings in format "name=value".

NOTE

If this property is not set, the subprocess will inherit the environment from its parent process.

Specifying a soft timeout for child termination

Since Wrapper version 3.5.5, it is also possible to specify a soft timeout for each process individually. The Wrapper will give the child process the chance to terminate by itself gracefully, whereas for instance the java.lang.Process.destroy() method will always cause a forced shutdown, giving the process no chance on shutting down by itself. Before Wrapper version 3.5.5, the timeout was always 5 seconds, so in order to keep functionality consistent, the default value of timeout is 5 seconds.

The timeout can be specified during the child process creation with the WrapperProcessConfig class.

WrapperProcessConfig wpConfig = new WrapperProcessConfig().setSoftShutdownTimeout(10);

The configuration in the above example will tell the Wrapper to wait for up to 10 seconds for any child processes that got created with that configuration. If the child processes don't finish after 10 seconds, the Wrapper will kill them forcibly.

The following values for a timeout are possible:

  • >0:

    The amount of seconds the Wrapper waits for the child process to exit gracefully before forced termination.

  • 0:

    The Wrapper will instantly force the termination of the child process.

  • -1:

    The Wrapper will never force the termination of the child process, but wait indefinitely for the child process to finish by itself.

Creating a Child Process for the Active User

On Windows, WrapperProcessConfig.setCreateForActiveUser(boolean) can be used to specify if the child processes should be launched in the current active session rather than in the session where the service is running (a session in which the user has SE_TCB_NAME privilege with the OS). On non-Windows platforms or when launched in Console mode, the setting will be ignored silently.

The default value is FALSE.