Descripción de la Exec Nativa del Wrapper

Descripción

La funcción WrapperManager.exec() es una alternativa a Java-Runtime.exec() o Java-ProcessBuilder, que tiene la desventaja de usar el método fork(), que por su vez puede consumir demasiada memoria al crear un nuevo proceso en algunas plataformas. El problema en esas plataformas es que en el Proceso Padre que quiere iniciar un proceso secundario, fork() hace que se clone el heap de memoria del padre para el hijo. Esto duplicará la memoria utilizada por un corto tiempo. Con una aplicación relativamente grande que tiene una cuota de memoria cerca de la cuota de memoria del sistema, se puede fallar al crear una aplicación pequeña como ls, o la memoria será intercambiada en el disco duro (HD), lo que reduce drásticamente el rendimiento.

Otro problema es facilitar la vinculación o separación del proceso hijo del padre mientras se inicia. Si el proceso Java se termina de forma esperada o inesperada, el Wrapper limpiará todos los procesos vinculados que aún no se hayan terminado.

Para mejor consistencia, se ha implementado la funcción WrapperManager.exec() lo más as parecido posible a la funcción Runtime.exec() en Java.

Ejecución

Inicio

Esta sección le mostrará enseguida como ejecutar un comando. (Más detalles serán explicados paso a paso por la página)

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

La línea anterior ejecutará un comando ls con los parámetros -l, -i, -s, y -a, y asignará un objecto WrapperProcess representando el proceso.

Si no se ha pasado la ruta completa del archivo binario (o script), se verificará el directorio de trabajo actual, así como los directorios PATH de los sistemas, y se ejecutará la primera opción encontrada. También se permite el direccionamiento relativo a partir del directorio de trabajo actual.

NOTA

El comando exec acepta el comando tanto como una Cadena Única (String) o como una Matriz de Cadenas (StringArray). En el caso de un StringArray, cada parámetro es ubicado en un solo campo de matriz.

I/O (Entrada/Salida) del Proceso

El proceso hijo creado se ejecuta en segundo plano en el sistema operativo y normalmente no es visible, siempre que no sea una aplicación de GUI (Interfaz gráfica de usuario). Para comunicarse con el proceso, la clase WrapperProcess provee 3 metodos para acceder a la entrada (Input) del processo, así como a la salida (Output) y los mensages de error (ErrorMessages) del proceso.

Se recomienda envolver el StreamObject devuelto con un BufferedReader. Para abrir el lector (Reader), por favor, proceda como se describe.

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

Esto establece el Lector del InputStream en el cual el hijo escribe su salida. Para leer datos de ErrorStream o escribir datos en el Hijo, proceda de manera similar a este ejemplo.

Una vez que el Reader/Writer se ha establecido, podemos leer/escribir de la siguiente forma:

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

NOTA

Recuerde que al seguir este ejemplo, todos los datos se leerán hasta que el proceso hijo cierre la transmisión por su lado.

Configuración del Proceso Hijo

Al ejecutar un comando, WrapperManager también brinda la posibilidad de configurar el proceso hijo. Esto se hace pasando un objecto WrapperProcessConfig a la funcción exec(). En la siguiente sección se explicarán las Configuraciones que puede realizar WrapperProcessConfiguration.

Proceso Desvinculado

El método setDetached() le permite especificar si el subproceso se ejecutará "desvinculado" del Wrapper. Si se marca el proceso como "desvinculado", el proceso no necesitará terminar quando el Wrapper esté terminando. Si no está marcado, el Wrapper realizará un seguimiento del proceso secundario e intentará finalizar el proceso si el proceso padre debe finalizar.

NOTA

Por defecto, los procesos no se iniciarán desvinculados de sus procesos padres.

Tipo de Inicio

El método setStartType() especifica un tipo de inicio de cómo el sistema operativo iniciará el subproceso.

ADVERTENCIA

Esta propiedad no es válida en Windows.

  • FORK_EXEC:

    Este es el método más comun de iniciar un proceso hijo en Linux/UNIX. Sin embargo, en algunos sistemas operativos (especialmente Solaris), esta llamada hará que la memoria del padre sea duplicada para el hijo inicialmente. En z/OS, este tipo de inicio no es compatible desde la versión inicial. En sistemas HP-UX, el Wrapper automáticamente usará vfork() en vez de fork().

  • VFORK_EXEC:

    La funcción vfork() solamente es diferente de fork() cuando el proceso hijo puede compartir código y datos con el proceso padre. Esto acelera significantemente la actividad de clonación con el consiguiente riesgo para la integridad del proceso padre si se usa vfork() equivocadamente. En algunos sistemas, vfork es igual a fork. En z/OS, este tipo de inicio no es compatible desde la versión inicial.

  • POSIX_SPAWN:

    El proceso se generará y no causará ninguna duplicación de memoria POSIX_SPAWN API. Esto solo está disponible en Linux, Solaris (10+), AIX, z/OS, MacOS, y FreeBSD 8+ (desde la versión 3.5.46).

  • DYNAMIC:

    El tipo de inicio óptimo se seleccionará automáticamente de acuerdo con el sistema operativo en el que se ejecuta el Wrapper. Tenga en cuenta que esta propiedad también implica que no se admitirá el cambio del directorio de trabajo debido a que no se admite el cambio del directorio de trabajo cuando se usa POSIX_SPAWN. Hay una propiedad experimental wrapper.child.allowCWDOnSpawn que podría usarse para lograr cambiar el directorio de trabajo.

NOTA

Por defecto, los procesos se iniciarán usando el tipo de inicio DYNAMIC.

Directorio de Trabajo

El método setWorkingDirectory() especifica el directorio de trabajo de los subprocesos, o "NULL" si el subproceso debe heredar el directorio de trabajo del proceso actual.

Por favor tenga en nota que no es posible configurar el directorio de trabajo directamente cuando se usa POSIX_SPAWN. Una solución sugerida sería envolver el comando que desea ejecutar en un script y realizar un cambio de directorio antes de la ejecución del comando.

#!/bin/sh

chdir $1
shift
$*

NOTA

Si no se configura esta propiedad, el subproceso heredará el directorio de trabajo de su proceso padre.

wrapper.child.allowCWDOnSpawn

La propiedad wrapper.child.allowCWDOnSpawn controla si el Wrapper intentará cambiar el directorio de trabajo para los tipos de inicio POSIX_SPAWN y DYNAMIC.

Esta propiedad es experimental y podría generar problemas si el proceso envuelto está usando un Código de Interfaz Nativo de Java e intentaría crear un proceso hijo usando POSIX_SPAWN.

Por defecto, esta propiedad se establece en FALSE.

wrapper.child.allowCWDOnSpawn=TRUE

Configurar Entorno

El método setEnvironment() especifica en entorno del subproceso creado.

Este campo es una matriz de cadenas. Cada elemento tiene configuraciones de variables de entorno en formato "nombre=valor" (name=value).

NOTA

Si no se configura esta propiedad, el subproceso heredará el entorno de su proceso padre.

Especificar Tiempo de Espera Flexible para Terminar un Proceso Hijo

Desde la versión Wrapper 3.5.5, también es posible especificar un tiempo de espera flexible para cada proceso individualmente. El Wrapper dará al proceso hijo la oportunidad de terminar por sí mismo de forma limpia, mientras que por ejemplo el método java.lang.Process.destroy() siempre causará un cierre forzado, no dando al proceso la oportunidad de cerrarse por sí mismo. Antes de la versión Wrapper 3.5.5, el tiempo de espera era siempre de 5 segundos, y para mantener la coherencia de la funcionalidad, el valor por defecto es 5 segundos.

El tiempo de espera se puede especificar mientras se crea el proceso hijo con la clase WrapperProcessConfig.

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

La configuración en el ejemplo anterior le indicará al Wrapper que espere hasta 10 segundos por cualquier proceso hijo que fue creado con esa configuración. Si los procesos hijos no terminan después de 10 segundos, el Wrapper los cerrará a la fuerza.

Se acceptan los valores suguientes para tiempo de espera:

  • >0:

    El número de segundos que el Wrapper espera para que el proceso hijo termine correctamente antes de forzar la terminación.

  • 0:

    El Wrapper forzará instantáneamente la terminación del proceso hijo.

  • -1:

    El Wrapper nunca forzará la terminación del proceso hijo, sino que esperará indefinidamente a que el proceso hijo termine por sí mismo.

Crear un Proceso Hijo para el Usuario Activo

En Windows, WrapperProcessConfig.setCreateForActiveUser(boolean) se puede usar para especificar si los procesos hijos deben iniciarse en la sesión activa actual en lugar de en la sesión donde se ejecuta el servicio (una sesión en la que el usuario tiene el privilegio SE_TCB_NAME con el sistema operativo). En plataformas diferentes de Windows, o cuando se lanzan en modo Consola, la configuración se ignorará silenciosamente.

El valor predeterminado es FALSE.