• Keine Ergebnisse gefunden

5 Übersetzung des Scopes

5.2 Fault Handlers

Ein FaultHandler kann in einer Scope-Aktivität oder in einem Prozess anhand des faultHandlers-Elements spezifiziert werden. BPEL bietet die Möglichkeit fehler-behandelnde Aktivitäten zu definieren, die in und catchAll-Elementen definiert werden. Jedes catch-Konstrukt kann anhand des faultName-Attributes einen bestimmten Fehler abfangen, der durch einen QualifiedName [W3C06] definiert ist. Durch das optionale faultVariable-Attribut können weitere Daten zu dem Fehler spezifiziert werden. Wenn das faultName-Attribut nicht spezifiziert ist, dann wird das catch-Element alle Fehler mit demselben Typ von Daten abfangen. Der Typ wird durch das faultMessageType- oder faultElement-Attribut definiert.

Durch das catchAll-Element können Fehler behandelt werden, die nicht durch ein spezielles catch-Element abgefangen werden konnten.

Es existiert eine Vielzahl an Möglichkeiten, Fehler in BPEL zu signalisieren. Beispiele dafür sind: eine invoke-Aktivität, die eine Request-Response-Operation spezifiziert und als Antwort eine Fehlernachricht empfängt. Der Fehlername und die Fehlerdaten basieren dabei auf der Definition in der entsprechenden WSDL-Operation. Eine andere Fehlerquelle ist die throw-Aktivität mit expliziten Fehlername und/oder Fehlerdaten. BPEL selbst definiert eine Menge an Standardfehlern, die durch ihren Namen identifiziert werden.

Die Daten, die einen Fehler näher spezifizieren, können entweder vom Typ WSDL-Message [W3C01] oder ein XML-Schema Element [W3C04a] sein. Jedes catch-Konstrukt, das ein faultName-Attribut mit einem QualifiedName als Wert enthält, kann nur Fehler mit dem gleichen QualifiedName abfangen. Aufgrund des BPEL Fehlernamen-Modell können Fehler mit dem gleichen QualifiedName, die in unterschiedlichen WSDL-Operationen aus dem gleichen Namespace definiert sind, von dem gleichen catch-Konstrukt abgefangen werden.

[OAS07a] definiert die Kriterien, nach denen Fehler an die einzelnen FaultHandlers weitergereicht werden. Dabei wird ganz allgemein unterschieden zwischen Fehler mit oder ohne spezifizierte Fehlerdaten. Bei XML-Schema Element basierten Daten wird zusätzlich die

<faultHandlers>

<catch faultName="lns:BookOutOfStockException"

faultVariable="BookOutOfStockVariable">

faultMessageType=“lns:OrderFaultType“

<reply …/>

Durch die rethrow-Aktivität kann ein BPEL-Prozess einen Fehler an den FaultHandler des Vater-Scopes weiterreichen. Die rethrow-Aktivität darf nur innerhalb eines FaultHandlers benutzt werden. Unabhängig davon, wie der Fehler abgefangen wurde und ob der FaultHandler die Fehlerdaten modifiziert hat, werden durch die rethrow-Aktivität immer die ursprünglichen Daten mit ihrem Typ weiterpropagiert.

Wenn ein Fehler in einem Prozess oder Scope-Aktivität signalisiert wird, dann betrachtet man die Terminierung dieses Prozesses als fehlerhaft, unabhängig davon, ob ein FaultHandler den Fehler abgefangen hat und ihn an den Vater-Scope weitergereicht hat oder ihn selbst verarbeitet hat. Der CompensationHandler wird für so einen Prozess nicht installiert.

Wenn der FaultHandler den Fehler nicht an den Vater-Scope weitergereicht hat, dann muss der Status aller Links (vgl. Abschnitt 4.7), die die umgebende Scope-Aktivität als Source-Aktivität haben, evaluiert werden.

In einem Prozess oder Scope-Aktivität darf nicht mehr als einer FCT-Handler aktiviert werden. Das Verhalten eines FaultHandlers beginnt mit der Terminierung aller Aktivitäten, die sich in dem umgebenden Scope befinden und aktiv sind. Die Terminierung dieser Aktivitäten muss sichergestellt werden, bevor die Aktivität des FaultHandlers gestartet wird.

Wird bei der Ausführung des FaultHandlers einen Fehler signalisiert, dann muss die Aktivität, die in diesem FaultHandler enthalten ist, terminiert werden. Der Fehler wird an den FaultHandler des Vater-Scopes gereicht.

Wenn der catchAll-FaultHandler für einen Scope nicht vorhanden ist, dann spezifiziert [OAS07a] für einen solchen Scope einen impliziten Default-FaultHandler. Das Verhalten dieses FaultHandlers wird spezifiziert als alle Kinder-Scopes zu kompensieren und den Fehler an den Vater-Scope zu propagieren.

Listing 20 zeigt die Definition des Default-FaultHandlers.

<catchAll>

In Abbildung 22 ist das FaultHandler-EWFN dargestellt.

eingebettete Aktivität repräsentiert. Die Transitionen T1, T2 und T3 regeln den Kontrollfluss.

Die Schnittstelle des FaultHandler-EWFNs besteht aus einer Vielzahl an Plätzen, von denen einigen mit Plätzen von umgebenden, benachbarten oder eingebetteten Aktivitäten identisch sind. Die rethrow-Aktivität ist ebenfalls in dem FaultHandler-EWFN eingezeichnet, da diese nur in einem FaultHandler spezifiziert werden darf. Da diese Aktivität in einem beliebigen catch-Zweig vorkommen kann und dieser jede BPEL-Aktivität enthalten kann, ist die Schnittstelle der rethrow-Aktivität identisch mit der generischen Schnittstelle aller EWFNs.

Bei der Übersetzung des FaultHandlers liegt die Schwierigkeit in der großen Anzahl an EWFNs, die miteinander verknüpft werden müssen sowie in der Berücksichtigung aller Szenarien, die bei der Ausführung einer Prozessinstanz eintreten können.

Als erstes werden die Plätze erläutert über die das EWFN Signale von außen empfängt bzw.

an seine Umgebung sendet. Danach wird die Kontrollflussevaluierung anhand von einigen Szenarien beschrieben.

Das FaultHandler-EWFN empfängt und sendet Signale zu dem umgebenden Scope durch die Plätze State und ended. Die Schnittstelle zu der primären Aktivität des umgebenden Scope bilden die Plätze start und fault. Der start-Platz ist identisch mit dem ended-Platz der primären Aktivität. Über den fault-Platz werden Fehler von allen Aktivitäten, die in der primären Aktivität eingeschlossen sind und sich nicht in einem Scope befinden, empfangen.

Über den failed-Platz wird ein Fehler an den FaultHandler des Vater-Scopes hochgereicht oder der Fehler wird an einen TerminationHandler (vgl. Abschnitt 5.4) oder eine Compensation-Aktivität (vgl. Abschnitt 5.6) signalisiert, wenn sich der umgebende Scope unmittelbar in einem TerminationHandler oder einer Compensation-Aktivität befindet. Dieser Platz ist identisch mit dem failed-Platz des umgebenden Scopes Die Plätze CF_inner und F_inner bilden die Schnittstelle zu den eingebetteten Aktivitäten. Das Terminieren von Aktivitäten wird über die Plätze from_MW, to_MW, terminate_FH, terminated_FH, terminate_CS und terminated_CS geregelt. In dem F_save-Platz werden die Fehlerdaten gespeichert. Diese stehen dadurch nur für die Aktivitäten in dem FaultHandler zur Verfügung. Zusätzlich werden in diesem Platz die Fehlerdaten gesichert, die später durch eine rethrow-Aktivität benötigt werden.

Im ersten Szenario wird der Fall betrachtet, dass innerhalb der primären Aktivität des umgebenden Scopes einen Fehler signalisiert wird. Weiterhin wird angenommen, dass der FaultHandler den Fehler bearbeiten kann und zwar ohne einen weiteren Fehler zu signalisieren. Da der fault-Platz mit den failed-Plätzen aller Aktivitäten, die einen Fehler signalisieren können identisch ist, liegt ein Tupel der Form (faultName, faultData, faultType) auf diesem Platz, wenn der signalisierte Fehler mit Fehlerdaten assoziiert ist. Die Transition T1 liest den Zustand des umgebenden Scopes aus. Wenn der Zustand running ist, dann wird er auf den Wert failed gesetzt. Dazu ist eine write-Kante zu dem State-Platz eingezeichnet.

Zusätzlich wird der Fehler-Tupel auf den Platz F_save geschrieben. Das ist notwendig in anderen Szenarien, wo der Fehler an den FaultHandler des Vater-Scopes durch die rethrow-Aktivität hoch gereicht werden muss. Dabei müssen die Daten sowie der Typ zu dem Fehler unverändert bleiben. Wenn der Zustand terminating oder failed ist, dann wird das empty-Tupel signalisiert. In dem Zustand terminating wird eine ForcedTermination vom Vater-Scope ausgeführt und deswegen wird der FaultHandler nicht laufen. In dem Zustand failed kann sich der umgebende Scope nur dann befinden, wenn einen Fehler bereits signalisiert worden ist. Alle anderen Zustände können nicht vorkommen. Ist der Zustand des umgebenden Scope running besteht die erste Aufgabe des FaultHandlers die primäre Aktivität sowie alle laufenden EventHandler-Instanzen zu terminieren. Dazu wird die Middleware-Komponente

über den Platz to_MW augerufen. Dieser Platz ist identisch mit dem gleichnamigen im umgebenden Scope und in ihm wird ein Tupel mit dem Wert scope geschrieben. Zusätzlich wird über den Platz terminate_CS den Kontrollfluss in allen Kinder-Scopes beendet. Dieser Platz ist mit dem terminate Platz aller Kinder-Scopes identisch. Diese werden wiederum ihren Kontrollfluss beenden, so dass zum Schluss soviel Tokens auf dem Platz terminated_CS liegen, wie die Anzahl der Kinder-Scopes ist. Anschließend wartet die Transition T1 auf ein Token in dem from_MW-Platz. Dadurch wird sichergestellt, dass die Middleware-Komponente alle CF-Tokens in der primären Aktivität durch entsprechende DP-Tokens ersetzt hat. Als nächstes wartet T1 auf ein FAIL-Token auf dem ended-Platz der primären Aktivität, sowie auf die Tokens in dem terminated_CS-Platz. An dieser Stelle ist es sichergestellt, dass keine weiteren Fehler auf den fault-Platz landen können sowie, dass alle Aktivitäten in dem umgebenden Scope den Status ihrer Links auf den Wert false gesetzt haben (durch das FAIL-Token). Nun kann T1 anhand der spezifizierten catch- und catchAll-Elementen diejenige innere Aktivität aktivieren, die in diesem catch-Zweig enthalten ist.

Dazu wird ein CF-Token auf den start-Platz dieser Aktivität geschrieben und ein DP-Token auf die start-Plätze aller anderen inneren Aktivitäten. Damit wird garantiert, dass diejenigen Aktivitäten in dem FaultHandler, die nicht zu Ausführung kommen den Status ihrer Links auf den Wert false setzen werden. Zusätzlich speichert T1 die Fehlerdaten in dem F_save-Platz in einer Variablen, dessen Namen dem Wert des faultVariable-Attributs des ausgewählten catch-Konstrukts entspricht. Werden keine Fehlerdaten übertragen oder spezifiziert das ausgewählte catch-Konstrukt kein faultVariable-Attribut, dann wird der letzte Schritt ausgelassen. Irgendwann werden die ended-Plätze aller inneren Aktivitäten CF- (nur diejenige Aktivität, die den Fehler abgefangen hat) und DP-Tokens enthalten. Dadurch wird die Transition T2 schalten und ein CF-Token auf dem ended-Platz des FaultHandler-EWFNs produzieren. Die write-Kante zu dem Platz CF_inner wird in dem nächsten Szenario erläutert.

Im zweiten Szenario wird der Fall betrachtet, dass bei der Ausführung der entsprechenden inneren Aktivität einen Fehler signalisiert wird. In diesem Fall müssen alle Aktivitäten in dem FaultHandler terminiert werden und der Fehler wird an den FaultHandler des Vater-Scopes propagiert. In diesem Fall betrachtet man die Kontrollflussevaluierung ab der Stelle, wo eine der catch-Aktivitäten aktiviert worden ist. Ein Fehler bei der Bearbeitung einer Aktivität in diesem catch-Konstrukt bedeutet, dass der Fehler in dem F_inner-Platz des FaultHandler-EWFNs landet. Die Transition T3 wird schalten und die Terminierung der Aktivitäten im FaultHandler veranlassen. Dafür schreibt T3 einen Tupel mit dem Wert fh in den to_MW-Platz. Das Terminieren der inneren Aktivitäten läuft ähnlich, wie das Terminieren der primären Aktivität des umgebenden Scopes. Der terminate_FH-Platz ist identisch mit den terminate-Plätzen aller Kinder-Scopes des FaultHandlers. Über den Platz terminated_FH werden die Tokens empfangen, die das Terminieren eines Kinder-Scopes bestätigen. Bevor der Kontrollfluss zurück an den umgebenden Scope zurückgeht, muss das Setzen des Status aller Links der inneren Aktivitäten gewährleistet werden. Deswegen schreibt T3 ein FAIL-Token auf den ended-Platz des FaultHandler-EWFNs erst nachdem ein FAIL-FAIL-Token auf dem CF_inner-Platz vorhanden ist. Dieses Token wird die Transition T2 schreiben, nachdem auf

Transition T2 schaltet, wenn die DP-Tokens auf den ended-Plätzen aller Aktivitäten liegen.

Danach schreibt die Transition T2 ein DP-Token auf den ended-Platz des FaultHandler-EWFNs.

Im vierten Szenario bettet die innere Aktivität des FaultHandlers, die den Fehler abgefangen hat, eine rethrow-Aktivität. In diesem Fall liegt ein CF-Token auf dem start-Platz des rethrow-EWFNs. Die einzige Transition im rethrow-EWFN schreibt ein FAIL-Token auf den ended-Platz. Dadurch wird an den nachfolgenden Aktivitäten signalisiert, dass sie nicht zur Ausführung kommen werden, da der Kontrollfluss an den Vater-Scope weitergehen wird. Als nächstes entfernt die rethrow-Transition den gesicherten Fehler aus dem F_save-Platz und schreibt diesen in den F_inner-Platz. In diesem Szenario wartet T3 genauso wie im Szenario 2 auf ein FAIL-Token auf dem CF_inner-Platz. Danach wird wie im Szenario 2 vorgegangen.