Wrapper Native Execute Overview

Overview

The WrapperManager.exec() function is a powerful alternative to Java-Runtime.exec() or Java-ProcessBuilder. Historically designed to be more memory-efficient than early Java implementations, which relied heavily on standard fork(), WrapperManager.exec() provides multiple starting configurations and lets you fine tune the system-level mechanism to launch child processes.

A key feature is its ability to seamlessly bind or detach child processes from the parent. If the main Java process terminates (either normally or unexpectedly), the Wrapper automatically cleans up any remaining bound processes that are still running.

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 macOS, this Start Type is no longer supported as of version 3.7.0 and is resolved to DYNAMIC.

  • 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 is automatically selected according to the OS the Wrapper is running on. Starting with Wrapper version 3.7.0, DYNAMIC resolves to POSIX_SPAWN by default. However, if a custom working directory is configured on a platform where WrapperProcessConfig.isWorkingDirectorySupported() returns false, it automatically falls back to FORK_EXEC to safely ensure the child process executes within the requested 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.

Before Wrapper version 3.7.0, it was not possible to set the working directory directly when using POSIX_SPAWN. A suggested workaround was 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
$*

Starting with Wrapper version 3.7.0, the setWorkingDirectory() method is supported when using POSIX_SPAWN on most modern Unix platforms, including Linux (glibc 2.29 or later), macOS (10.15+), FreeBSD (13.1+), and Solaris (11.3+). AIX does not yet support this capability; however, the implementation is forward-compatible and support will be automatic if IBM adds the capability in a future OS update. It is possible to use the isWorkingDirectorySupported() method at runtime to verify platform compatibility before attempting to set a working directory.

NOTE

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

wrapper.child.allowCWDOnSpawn (deprecated as of 3.7.0)

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

WARNING

This property was originally introduced as experimental and has been deprecated in version 3.7.0 because it is unsafe for multi-threaded applications. Because it temporarily changes the global working directory of the parent JVM, it can introduce severe race conditions. This can cause concurrent threads to resolve relative file paths incorrectly and can break native (JNI) code attempting to spawn processes.

On most modern Unix platforms this property is not required, and the alternative setWorkingDirectory() method is preferred (if using Wrapper version 3.7.0 or above). To verify if setting the working directory is supported on the current platform and prevent runtime errors, use the isWorkingDirectorySupported() method.

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.