SOAP Web Services mit JAX-WS

Interzeptoren für Web Services

JAX-WS unterstützt außerdem Interzeptoren, wenngleich diese hier Handler heißen [6]. Das ist ein sehr mächtiges Konzept, das es dem Programmierer ermöglicht, auf alle ein- und ausgehenden Nachrichten einzuwirken. Je nachdem, auf welcher Ebene ein Handler seine Arbeit verrichtet, spricht man vom SOAP Handler oder vom logischen Handler. Nachdem diese sowohl auf der Client- als auch auf der Web-Service-Seite zum Einsatz gelangen können, lassen sich damit sehr elegant Erweiterungen realisieren (Abb. 1).

Abb. 1: Abfolge eines Web-Service-Aufrufs mit client- und serverseitigen Handlern [6]

So kann man beispielsweise einen clientseitigen Handler implementieren, der im SOAP Header aller ausgehenden Nachrichten automatisch die Authentifizierungsdaten des Clients ergänzt. Sein Gegenstück auf Seite des Web Service prüft dann für alle eingehenden Nachrichten, ob der Header gültige Benutzerdaten enthält. Ist das nicht der Fall, so wird die Nachricht zurückgewiesen und erreicht den adressierten Empfängerdienst gar nicht. Das Schöne dabei ist, dass solche Erweiterungen gegenüber dem eigentlichen Web Service vollkommen transparent bleiben. Die Komplexität der eigentlichen Businesslogik wird dadurch also nicht zusätzlich aufgebläht.

Aus Implementierungssicht handelt es sich bei Handlern um einfache Klassen, die je nach Typ entweder das Interface SOAPHandler<SOAPMessageContext> oder das Interface LogicalHandler<LogicalMessageContext> implementieren. Beim Passieren einer Nachricht wird die Methode handleMessage()jedes aktivierten Handlers aufgerufen. Über den Kontext lässt sich feststellen, ob es sich um eine ein- oder ausgehende Nachricht handelt. Ebenfalls ermöglicht jener den Zugriff auf die Nachricht. Das Zurückliefern von false oder das Werfen einer RuntimeException beziehungsweise einer ProtocolException innerhalb der Methode verhindert die Nachrichtenweiterleitung. Anhand der Hauptmethode eines SOAP Handlers, der sämtliche Nachrichten auf der Standardausgabe mitprotokolliert, kann dieser Sachverhalt nachvollzogen werden (Listing 10).

Listing 10
public boolean handleMessage(SOAPMessageContext context) {
  try {
    boolean incoming = !(Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
    System.out.println((incoming ? "Incoming" : "Outgoing") + " message");

    SOAPMessage message = context.getMessage();
    message.writeTo(System.out);

    return true;
  }
  catch (Exception e) {
    throw new RuntimeException(e);
  }      
}

Nun bleibt nur mehr zu klären, wie sich solche Handler aktivieren lassen. Dazu muss ihr Klassenname in einer Handler-Kette eingetragen und diese danach dem Client oder dem Web Service zugeordnet werden. Bei Clients erfolgt dieser Vorgang üblicherweise mithilfe entsprechender Java-Anweisungen (Listing 11). Im konkreten Beispiel würde jeder nachfolgende Web-Service-Aufruf clientseitig den Handler CalculatorClientHandlerSecurity durchlaufen. In Verbindung mit einem Web Service trägt der Entwickler die Namen der Handler-Klassen in einer XML-Datei ein (Listing 12). Durch das Annotieren des SEI (oder der SIB) mit @HandlerChain und entsprechendes Setzen des Attributs file schließt sich der Kreis:

@WebService(serviceName="CalculatorWSService",
            portName="CalculatorWSPort")
@HandlerChain(file="calculator-handler-chain.xml")
public interface CalculatorWS { ... }

Zu beachten ist, dass das System die XML-Datei an der angegebenen Stelle im Klassenpfad finden können muss.

Listing 11
...
BindingProvider bindingProvider = (BindingProvider) calculatorWS;
Binding binding = bindingProvider.getBinding();

List handlerChain = binding.getHandlerChain();
handlerChain.add(new CalculatorClientHandlerSecurity("abauer", "magic"));
binding.setHandlerChain(handlerChain);
Listing 12

        de.javamagazin.calculator.CalculatorWSHandlerSecurity
      
Fazit und Ausblick

Der Artikel gab eine theoretische Einführung in SOAP Web Services und JAX-WS und zeigte anschließend anhand eines Berechnungsdienstes, wie einfach sich solche Komponenten mittlerweile realisieren lassen. Ein paar Annotationen hier, ein paar Annotationen da und schon ist in den meisten Fällen der Löwenanteil der Web-Service-spezifischen Arbeit erledigt. Das ermöglicht dem Entwickler, sich fast gänzlich auf die Implementierung der eigentlichen Businesslogik konzentrieren zu können. Fairerweise muss aber festgehalten werden, dass der Artikel nur eine Einführung in die insgesamt doch recht komplexe Materie gab. Wichtige Themen, beispielsweise Sicherheit, wurden bewusst ausgespart, da diese den Rahmen gesprengt hätten.

Im nächsten Teil der Serie werden wir uns mit der Realisierung von RESTful Web Services mit JAX-RS beschäftigen. Jene entstanden unter anderem aus der Motivation heraus, dem Nutzer eine leichtgewichtigere Web-Service-Variante zur Verfügung zu stellen.

Bernhard Löwenstein (b.loewenstein[at]gmx.at) arbeitet als Projektleiter und Softwareentwickler für die Potsdamer Intervista AG. Er ist außerdem als IT-Trainer tätig und schreibt laufend Artikel für verschiedene deutsche Fachmagazine.
Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.