Wrapper Native Execute Übersicht

Übersicht

Die WrapperManager.exec() Funktion ist eine Alternative zu der Java-Runtime.exec() oder Java-ProcessBuilder-Funktion, die den Nachteil hat, dass diese die fork()-Methode benutzt, die auf gewissen Plattformen sehr speicheraufwändig sein kann, um einen neuen Prozess zu erstellen. Das Problem auf diesen Plattformen ist, dass innerhalb des Elternprozesses, der einen Nebenprozess starten möchte, fork() bewirkt, dass der Memory-Heap des Eltern- auf den Kindprozess nachgebildet wird. Dies verdoppelt den beanspruchten Speicher innerhalb kurzer Zeit. Im Fall einer ziemlich großen Anwendung, die an die Speicherquoten des Systems heranreicht, kann es vorkommen, dass es nicht gelingt, auch nur eine kleine Anwendung zu starten, z.B. ls, oder dass der Speicher stark auf die Festplatte ausgelagert wird, was die Leistung drastisch reduziert.

Ein anderes Anliegen ist das Vereinfachen des Bindens und Lösens des Child-Prozesses vom Eltern-Prozess. Wenn der Java-Prozess erwartet oder unerwartet endet, wird der Wrapper alle verbundenen Prozesse, die bisher noch nicht beendet wurden, beenden.

Für bessere Konsistenz wurde die WrapperManager.exec()-Funktion so ähnlich wie möglich zu der Runtime.exec() Funktion in Java implementiert.

Ausführen

Start

Dieser Abschnitt wird Ihnen zeigen, wie ein Befehl ausgeführt werden kann. Weitere Details werden Schritt für Schritt, während Sie diese Seite lesen, erklärt.

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

Die oben genannte Zeile führt einen ls-Befehl mit den Parametern -l, -i, -s, und -a aus, und weist dann ein WrapperProcess-Objekt zu, welches den Prozess darstellt.

Wenn der vollständige Pfad der Programm- (oder Skript-) Datei nicht weiter gegeben wurde, werden das aktuelle Arbeitsverzeichnis wie auch die System-PATH-Verzeichnisse durchsucht; der erste gefundene Treffer wird ausgeführt. Relative Adressmethoden, die vom Arbeitsverzeichnis aus starten, werden auch unterstützt.

NOTE

Der exec-Befehl akzeptiert den Befehl entweder als einen einfachen String oder als StringArray. Im Fall eines StringArrays befindet sich jeder Parameter in einem single-array-Feld.

E/A des Prozesses

Der erstellte Child-Prozess läuft im Hintergrund des Betriebssystems und ist gewöhnlich nicht sichtbar, solange es keine GUI-Anwendung ist. Um mit dem Prozess zu kommunizieren, stellt die WrapperProcess-Klasse drei Methoden zur Verfügung, um auf die Eingabe, die Ausgabe sowohl als auch auf die Fehlermeldungen des Prozesses zuzugreifen.

Es wird empfohlen, das zurückgegebene StreamObject mit einem BufferedReader zu verpacken. Um den Reader zu öffnen, fahren Sie bitte wie folgt fort.

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

Dies erstellt den Reader von InputStream, in den der Child-Prozess seine Ausgabe hineinschreibt. Um Daten vom ErrorStream zu lesen oder um Daten zum Child-Prozess zu schreiben, fahren Sie bitte ähnlich zu folgendem Beispiel fort.

Sobald der Reader/Writer eingerichtet wurde, können wir Daten wie folgt lesen und schreiben:

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

NOTE

Bitte beachten Sie, dass durch das Folgen dieses Beispiels alle Daten gelesen werden bis der Child-Prozess den Stream auf seiner Seite schließt.

Konfiguration des Child-Prozesses

Wenn Sie einen Befehl ausführen, stellt der WrapperManager auch die Möglichkeit zur Verfügung den Child-Prozess zu konfigurieren. Dies wird getan, indem das WrapperProcessConfig-Objekt der exec()-Funktion übergeben wird. Der folgende Abschnitt erklärt die Konfigurationen, die von der WrapperProcessConfiguration erzeugt werden können.

Unabhängiger, eigenständiger Prozess

Die setDetached()-Methode bestimmt, ob der Unterprozess eigenständig vom Wrapper ausgeführt wird. Wenn der Prozess als eigenständig markiert ist, muss der Prozess nicht beendet werden, wenn der Wrapper sich beendet. Falls nicht markiert, wird der Wrapper den Child-Prozess im Auge behalten und versuchen, den Prozess zu beenden, sobald der Eltern-Prozess enden sollte.

NOTE

Standardmäßig werden Prozesse, die eigenständig von ihrem Elternprozess sind, nicht gestartet.

Starttyp

Die setStartType()-Methode bestimmt einen Starttyp, wie der Unterprozess vom Betriebssystem gestartet wird.

WARNING

Diese Eigenschaft hat keine Auswirkung auf Windows.

  • FORK_EXEC:

    Dies ist der am meisten gebräuchliche Weg, wie in Linux/UNIX ein Child-Prozess gestartet wird. Jedoch verursacht dieser Aufruf in ein paar Betriebssystemen (insbesondere Solaris), dass anfänglich der Speicher des Eltern- für den Child-Prozess verdoppelt wird. Unter z/OS wird dieser Starttyp seit dem Anfangsrelease nicht unterstützt. Auf HP-UX-Systemen wird der Wrapper automatisch umschalten, eher vfork() als fork() nutzen.

  • VFORK_EXEC:

    Die vfork()-Funktion unterscheidet sich von fork() nur darin, dass der Child-Prozess Programmcode und Daten mit dem Eltern-Prozess teilen kann. Dies beschleunigt die Cloning-Aktivität wesentlich zu Lasten des Risikos der Integrität des Eltern-Prozesses, falls vfork() falsch benützt würde. Auf ein paar Systemen ist vfork identisch mit fork. Unter z/OS wird dieser Starttyp seit dem Anfangsrelease nicht unterstützt.

  • POSIX_SPAWN:

    Prozess wird erzeugt und verursacht keine Verdopplung des Speichers (POSIX_SPAWN API).

    ? Please check the English version for a more recent version of this text.
    Dies ist nur unter Linux, Solaris (10+), AIX, z/OS und MacOS verfügbar.

  • DYNAMIC:

    Der optimale Starttyp wird automatisch ausgewählt werden, je nachdem unter welchem Betriebssystem der Wrapper ausgeführt wird. Bitte beachten Sie, dass dies auch voraussetzt, dass das Ändern des Arbeitsverzeichnisses nicht unterstützt wird; weil das Ändern des Arbeitsverzeichnisses bei Einsatz von POSIX_SPAWN nicht unterstützt wird. Es gibt eine Test-Eigenschaft wrapper.child.allowCWDOnSpawn, die genutzt werden könnte, um zu erreichen, dass die Änderung des Arbeitsverzeichnisses möglich wird.

NOTE

Standardmäßig werden Prozesse mit dem Starttyp DYNAMIC gestartet.

Arbeitsverzeichnis

Die setWorkingDirectory()-Methode bestimmt das Arbeitsverzeichnis des Teilprozesses, oder "NULL", wenn der Subprozess das Arbeitsverzeichnis des gegenwärtigen Prozesses erben sollte.

Bitte beachten Sie, dass es beim Einsatz von POSIX_SPAWN nicht möglich ist, das Arbeitsverzeichnis direkt festzulegen. Ein vorgeschlagener Workaround wäre es, den Befehl, den Sie auszuführen, in ein Skript zu schreiben und eine Änderung des Verzeichnisses vor dem Ausführen des Befehls durchzuführen.

#!/bin/sh

chdir $1
shift
$*

NOTE

Wenn diese Eigenschaft nicht gesetzt ist, wird der Unterprozess das Arbeitsverzeichnis von seinem Eltern-Prozess erben.

wrapper.child.allowCWDOnSpawn-Eigenschaft

Die wrapper.child.allowCWDOnSpawn-Eigenschaft steuert, ob der Wrapper das Arbeitsverzeichnis für den Starttyp POSIX_SPAWN und DYNAMIC versucht, zu ändern.

Diese Eigenschaft wird testweise zur Verfügung gestellt und könnte zu Problemen führen, wenn der eingeschlossene Prozess den Java Native Interface (JNI) Code benutzt und versuchen würde, einen Child-Prozess mittels POSIX_SPAWN zu erstellen.

Standardmäßig ist diese Eigenschaft auf FALSE eingestellt.

wrapper.child.allowCWDOnSpawn=TRUE

Festlegen der Umgebung

Die setEnvironment()-Methode legt die Umgebung des erstellten Unterprozesses fest.

Dieses Feld ist ein Array von Strings, jedes dieser hat Einstellungen zur Umgebungsvariablen im Format "name=value".

NOTE

Wenn diese Eigenschaft nicht gesetzt wurde, wird der Subprozess die Umgebung von seinem Eltern-Prozess erben.

Festlegen des Soft-Exit-Timeout

Seit der Wrapper Version 3.5.5 ist es auch möglich, ein Soft-Timeout für jeden Prozess individuell festzulegen; dabei wird der Wrapper dem Child-Prozess die Möglichkeit geben, sich selbst problemlos zu beenden. Währenddessen wird z.B. die java.lang.Process.destroy()-Methode stets ein Herunterfahren erzwingen, ohne dem Prozess die Möglichkeit zu geben, sich selbst zu beenden. Vor der Wrapper Version 3.5.5 betrug der Timeout stets 5 Sek., um die Funktionalität konsistent zu halten, ist der Standardwert des Timeouts 5 Sek.

Der Timeout kann während der Erstellung des Child-Prozesses mittels der WrapperProcessConfig-Klasse festgelegt werden.

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

Die Konfiguration in dem obengenannten Beispiel sagt dem Wrapper, bis zu 10 Sekunden Child-Prozess, der mit dieser Konfiguration erstellt wurde, zu warten. Wenn die Child-Prozesse sich nach 10 Sekunden nicht beenden, wird der Wrapper diese zwangsweise beenden.

Die folgenden Werte eines Timeouts sind möglich

  • >0:

    Anzahl der Sekunden, die der Wrapper mindestens wartet, damit sich der Child-Prozess fehlerfrei beenden kann, bevor die Beendigung erzwungen wird.

  • 0:

    Der Wrapper erzwingt die Beendigung des Child-Prozesses sofort.

  • -1:

    Der Wrapper erzwingt nie die Beendigung des Child-Prozesses, sondern wartet zeitlich unbeschränkt auf den Child-Prozess, sich selbst zu beenden.

Erstellen eines Child-Prozesses für aktive User

Unter Windows kann WrapperProcessConfig.setCreateForActiveUser(boolean) genutzt werden, um zu spezifizieren, ob die Kindprozesse eher in der aktuellen aktiven Sitzung gestartet werden sollen als in der Sitzung, in der der Dienst läuft (eine Sitzung, in der der User SE_TCB_NAME Privileg mit dem Betriebssystem hat). Unter Nicht-Windows-Plattformen oder gestartet im Konsolenmodus, wird die Einstellung stillschweigend ignoriert.

Der Standardwert ist FALSE.