Suche

Gerippe für Java-Seifenkisten

Apache CXF

Das derzeit wohl mächtigste Java-Web-Service-Framework entstand aus den besten Teilen der beiden Produkte Celtix und XFire, wodurch sich auch der Name CXF (CeltiXFire) erklärt. Es lassen sich damit SOAP und RESTful Web Services realisieren. In beiden Fällen kann der Entwickler auf den jeweiligen Java-Standard zurückgreifen. Hinsichtlich der Vorgehensweise hat er die Wahl zwischen Code First und Contract First. CXF besticht durch vielfältige Integrationsmöglichkeiten sowie eine große Zahl an Werkzeugen zur Codegenerierung. Von der Architektur her bildet der auf Spring basierende CXF-Bus das Rückgrat des Systems (Abb. 2). Er sorgt für die Bereitstellung der gemeinsamen Ressourcen und baut mittels Dependency Injection die in den Konfigurationsdateien definierten Dienste zur Laufzeit zusammen.

Abb. 2: Der CXF-Bus stellt die zentrale Komponente von Apache CXF dar

Die Entwicklung kann bei diesem Framework auf Basis eines einfachen Interface und einer einfachen Klasse, die es implementiert, erfolgen. Annotationen sind hierbei nicht nötig. CXF spricht in diesem Fall von Simple Frontends. In Sachen Data Bindung kann der Programmierer erneut aus dem Vollen schöpfen. Mit Aegis, JAXB, SDO (Service Data Objects), XML Beans und demnächst JiBX bleiben kaum Wünsche offen. Weiterhin unterstützt das Apache-Framework Interceptors. Der Entwickler kann diese sowohl client- als auch serverseitig in den CXF-Bus einhängen und teilt sie wiederum einer bestimmten Phase zu. Es handelt sich bei jenen um Klassen, die von org.apache.cxf.phase.AbstractPhaseInterceptor beziehungsweise einer Unterklasse abgeleitet sind (Listing 5). Die Phasenzuordnung nimmt er innerhalb ihres Konstruktors vor. Die Aktivierung erfolgt entweder programmatisch, per Annotation oder per Konfiguration. Das CXF-Release liefert diverse einsatzbereite Interceptors mit.

Listing 5
...
public class MyLoggingInInterceptor extends AbstractPhaseInterceptor {
  public MyLoggingInInterceptor() {
    super(Phase.RECEIVE);
  }  

  @Override
  public void handleMessage(Message message) throws Fault {
    try {
      InputStream in = message.getContent(InputStream.class);
      if (in != null) {
        CachedOutputStream cache = new CachedOutputStream();

        IOUtils.copy(in, cache);
        in.close();
        cache.close();

        System.out.println("Message: " + cache.getOut());

        message.setContent(InputStream.class, cache.getInputStream());
      }
    }
    catch (Exception e) {
      throw new Fault(e);
    }
  }
}

Verschiedene Strategien lassen sich beim Deployment verfolgen. So erlaubt CXF ein fast nahtloses Integrieren mit verschiedenen Applikationsservern und unterstützt JBI (Java Business Integration). Eine Standalone-Lösung ist ebenfalls verfügbar. Am portabelsten ist abermals das Ausliefern der Web Services in Form einer WAR-Datei. Als Front Controller kommt das Servlet org.apache.cxf.transport.servlet.CXFServlet zum Einsatz. Die Konfiguration des CXF-Busses sowie der Dienste erfolgt über Spring-Konfigurationsdateien. Neben den JAX-WS- und JAX-RS-konformen Web Services lassen sich auf diese Weise auch Simple Frontends hochziehen (Listing 6).

Listing 6

Es bleibt noch die Frage zu beantworten, wie sich ein Web Service mit CXF abfragen lässt. Das Framework stellt für diese Belange verschiedene Hilfsklassen bereit. Am einfachsten ist der Zugriff mithilfe der Klasse org.apache.cxf.frontend.ClientProxyFactoryBean beziehungsweise einer Unterklasse (Listing 7), am dynamischsten mit org.apache.cxf.endpoint.dynamic.DynamicClientFactory beziehungsweise einer Unterklasse. Nachdem bei der zweiten Variante allerdings der Operationsname als Zeichenkette und die Parameter als Object Array an die Methode invoke()zu übergeben sind, geht die Typsicherheit verloren. Dafür kann die Operationsausführung auch asynchron ablaufen. Das Generieren eines statischen Client-Stubs ist ebenfalls möglich. Das Tool java2wsdl ist hierfür das richtige.

Listing 7
ClientProxyFactoryBean factory = new ClientProxyFactoryBean();
factory.setServiceClass(CalculatorWS.class);
factory.setAddress("http://localhost:8080/cxf/services/CalculatorWS");

CalculatorWS calculatorWS = (CalculatorWS) factory.create();

User user = User.getUserExample();
calculatorWS.subscribeToNewsletter(user);
Metro

Metro ist die Referenzimplementierung für JAX-WS. Die Frage, welche Art von Web Services sich damit erstellen lassen, sollte somit einfach zu beantworten sein. Über Umwege können damit auch RESTful Web Services realisiert werden. Die Metro-Bibliotheken sind im JDK 6 enthalten. Sowohl Code First als auch Contract First werden unterstützt. Für diverse IDEs und Build-Werkzeuge existieren Plug-ins, die die Arbeit erleichtern.

Metro ist aber deutlich mehr als nur eine JAX-WS-Implementierung. Diese bildet nur den Kern des modular aufgebauten Web Service Stacks (Abb. 3) und baut auf etlichen eigenständigen Bibliotheken auf, z. B. der JAXB-Referenzimplementierung. Darüber hinaus stellt Metro unter dem Namen WSIT (Web Services Interoperability Technologies) [4] verschiedene Technologien bereit, die die Basisfunktionalitäten des Kerns erweitern. Es handelt sich dabei meist um Implementierungen von WS*-Features, die sich Themen wie Transport, Ausfallsicherheit, Transaktionen und Security annehmen. Ans Herz gelegt sei allen Lesern außerdem ein Blick auf das Unterprojekt JAX-WS Commons [5], das verschiedene über den JAX-WS-Standard hinausgehende Erweiterungen unter einem Dach zusammenfasst.

Abb. 3: Metro folgt einem modularen Aufbau, den Kern bildet die JAX-WS-Referenzimplementierung

Hinsichtlich der Entwicklung von Webdiensten, deren Deployment und ihrer Nutzung gilt das Gleiche wie im ersten Artikel. Wir wollen deshalb nicht näher darauf eingehen. In Sachen Data Binding ist JAXB bei Metro die einzige Option.

Kommentare

Schreibe einen Kommentar

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