← Zur Uebersicht

SOAP Faults

Beispiel: BillingRegistrationFault + BillingFaultDetail in novaris-common-legacy, geworfen von BillingServiceEndpoint, behandelt in BillingIntegrationBean.

Wie ein SOAP Fault entsteht

Ein SOAP Fault ist das SOAP-Aequivalent einer Exception - ein <soap:Fault>-Element in der Antwort, statt eines regulaeren Ergebnis-Elements. JAX-WS bildet das direkt auf Java-Exceptions ab:

@WebFault(name = "BillingRegistrationFault", targetNamespace = "http://billing.novaris.com/soap")
public class BillingRegistrationFault extends Exception {
    private final BillingFaultDetail faultInfo;
    // ...
    public BillingFaultDetail getFaultInfo() { return faultInfo; }
}

@WebFault markiert eine checked Exception als SOAP-Fault-faehig. Wirft die Server-Implementierung sie, serialisiert die JAX-WS-Laufzeit automatisch getFaultInfo() in das Fault-XML; der Client deserialisiert es beim Empfang zurueck in dieselbe Exception-Klasse (containerintern, voellig transparent fuer den aufrufenden Code - er sieht einfach eine ganz normale catch (BillingRegistrationFault e)-Klausel).

Zwei Fehlerarten, zwei Reaktionen

Genau wie bei EJB (siehe docs/10-ejb-konzepte/06-exceptions.md) lohnt sich die Unterscheidung zwischen einem fachlichen und einem technischen Fehler - nur ist der Mechanismus bei SOAP ein anderer:

Fachlicher Fehler Technischer Fehler
Beispiel Police bereits registriert, ungueltige Praemie Netzwerkausfall, Timeout, Server nicht erreichbar
Java-Typ BillingRegistrationFault (checked, @WebFault) javax.xml.ws.WebServiceException (unchecked)
Auf der Wire-Ebene strukturiertes <soap:Fault> mit Detail-XML i.d.R. gar keine SOAP-Antwort (Verbindung schlaegt fehl)
Sinnvolle Reaktion fachlich auswerten (reasonCode), ggf. anders behandeln erneut versuchen, dann als Systemausfall behandeln

BillingIntegrationBean behandelt beide bewusst unterschiedlich: ein BillingRegistrationFault wird sofort ausgewertet (kein Retry - andernfalls wuerde man denselben fachlichen Fehler nur wiederholt provozieren), ein WebServiceException wird einmal wiederholt, bevor aufgegeben wird.

Ein Fault kann mehrere fachliche Bedeutungen haben

BillingFaultDetail.reasonCode unterscheidet zwei Faelle, die derselbe Exception-Typ transportiert, aber die vollkommen unterschiedlich behandelt werden:

Der Lehrpunkt: ein einzelner Fault-Typ mit einem "reasonCode"-Unterscheidungsfeld ist in der Praxis haeufiger als ein eigener Fault-Typ pro Fehlerfall - er haelt die WSDL uebersichtlich, verlagert aber die Verantwortung, die einzelnen Faelle korrekt auseinanderzuhalten, auf den aufrufenden Code (siehe handleBusinessFault(...) in BillingIntegrationBean).

Ausblick: warum das auf Dauer nicht reicht

Diese Fault-Behandlung funktioniert nur, weil der Aufruf synchron ist - der Aufrufer wartet auf die Antwort und kann sofort entscheiden. Genau das ist zugleich das im BillingIntegrationBean-Javadoc beschriebene Risiko (synchroner externer Aufruf innerhalb einer CMT-Transaktion). Eine asynchrone Entkopplung (siehe Phase 3, docs/00-ueberblick/systemlandschaft.md) wuerde diese Art der direkten Fault-Behandlung durch ein anderes Muster ersetzen muessen (z.B. Antwort-Queue, Kompensation) - ein guter Vorgeschmack darauf, warum "SOAP synchron aufrufen" und "zuverlaessig asynchron integrieren" zwei grundverschiedene Architekturprobleme sind.

⌂ Cockpit