SOAP Web Services mit JAX-WS

Deployment eines Webservice

Zum Starten eines Web Service bieten sich verschiedene Möglichkeiten, die wir uns anhand des Kalkulatorservice anschauen wollen. Die einfachste Variante erfordert lediglich einen Einzeiler:

Endpoint endpoint = Endpoint.publish("http://localhost:8080/calculator",
                                     new CalculatorWSImpl());

Der Dienst wird dadurch an der übergebenen Adresse hochgezogen und kann dort gefunden werden. Mit endpoint.stop()lässt sich der veröffentlichte Endpunkt stoppen.

Das Deployen eines Web Service kann weiterhin unter Verwendung des von Java SE 6 bereitgestellten internen HTTP-Servers erfolgen (Listing 4). Die Angabe eines Backlogs, also der Maximalanzahl für die in der Queue auf die Arbeitung wartenden Requests, ist hier ebenfalls möglich.

Listing 4
HttpServer server = HttpServer.create(new InetSocketAddress(8080), 25);
HttpContext context = server.createContext("/calculator");
Endpoint endpoint = Endpoint.create(new CalculatorWSImpl());

endpoint.publish(context);
server.start();
...
endpoint.stop();
server.stop(0);

In produktiven Umgebungen erfolgt das Deployment der Web Services zumeist in Form von Webapplikationen. Bei Metro ist neben der web.xml (Listing 5), in der ein bestimmter Listener und ein bestimmtes Servlet eingetragen werden, noch eine Konfigurationsdatei namens sun-jaxws.xml (Listing 6) vonnöten. Hierin werden die Web-Service-Endpunkte definiert. Beide Dateien kommen im Webarchiv ins Unterverzeichnis WEB-INF, die kompilierten Klassen und Interfaces sind wie gewohnt in WEB-INF/classes einzuspielen.

Listing 5

      com.sun.xml.ws.transport.http.servlet.WSServletContextListener
    WSServlet
      com.sun.xml.ws.transport.http.servlet.WSServlet
    1WSServlet/*
Listing 6

Testen lässt sich das derart erstellte Webarchiv mit einem Server, der Metro an Bord hat. Das ist beispielsweise beim GlassFish 3.1 der Fall. Durch das Deployen der Datei unter dem Wurzelkontext, wird der Web Service sogleich unter derselben Adresse wie bei den ersten beiden Varianten hochgezogen.

Unabhängig von der gewählten Vorgehensweise gelangt man an die Schnittstellenbeschreibung eines Web Service, indem man ?wsdl an seinen eigentlichen URL anhängt. Im Falle des Kalkulators liefert demnach http://localhost:8080/calculator?wsdl die gewünschte Information.

Nutzung eines Web Service

Unser Berechnungsdienst ist implementiert und ausgerollt – nun will er natürlich auch genutzt werden. Hierbei sind grundsätzlich zwei Vorgehensweisen denkbar. Bei der einfacheren Variante greift der Entwickler mithilfe eines dynamischen Service Proxys auf den Web Service zu (Listing 7). Er benötigt dazu den URL zur Schnittstellenbeschreibung, den genauen Servicenamen – als Namenspace-URI wird standardmäßig der invertierte Packagename mit vorangestelltem http:// und abschließendem / verwendet – und das SEI.

Listing 7
URL wsdl = new URL("http://localhost:8080/calculator?wsdl");
QName serviceName = new QName("http://calculator.javamagazin.de/", 
                              "CalculatorWSService");

Service service = Service.create(wsdl, serviceName);
CalculatorWS calculatorWS = service.getPort(CalculatorWS.class);

System.out.println(calculatorWS.sum(1, 2));

Liegt ihm allerdings das SEI nicht vor, so muss er sich mit dem Tool wsimport [4] einen statischen Stub für den Zugriff auf den Web Service erstellen. In diesem Fall reicht es, die Adresse der Schnittstellenbeschreibung zu kennen. Um für unseren Kalkulator entsprechende Klassen zu generieren, müssen wir den folgenden Aufruf an der Kommandozeile absetzen:

wsimport -d classes -s src-generated -p de.javamagazin.calculator.generated http://localhost:8080/calculator?wsdl

Der Zugriff auf den Web Service erfolgt dann in ähnlicher Form wie beim dynamischen Service Proxy.

Doch halt – da war noch etwas! Wir wollten uns ja noch entsprechende Konstrukte zur asynchronen Ausführung von isPrimeNumber() generieren lassen [5]. Hierfür muss beim Toolaufruf zusätzlich der Name einer Bindingdatei übergeben werden:

wsimport -b calculator-binding.xml -d classes ...

In dieser Datei legt der Aufrufer fest, für welche Operationen asynchrone Methoden-Stubs generiert werden sollen. Im Falle des Kalkulators wählen wir lediglich die Methode isPrimeNumber()aus (Listing 8).

Listing 8
falsetrue

Das Tool erzeugt für jede selektierte Operation zwei asynchrone Methodenvarianten, die wie ihr synchrones Pendant heißen, allerdings auf Async enden. Eine dieser Methoden liefert ein Objekt zurück, das das Interface Response implementiert (Listing 9a). Darüber lässt sich einerseits abfragen, ob das Ergebnis bereits anliegt, und andererseits auf das Resultat zugreifen. Die zweite Methode erlaubt dem Entwickler, bei ihrem Aufruf ein AsyncHandler-Objekt mit zu übergeben (Listing 9b). Sobald das Ergebnis verfügbar ist, wird die Methode handleResponse()dieses Handlers aufgerufen. Dort erfolgt dann üblicherweise die weitere Verarbeitung.

Listing 9
...
// Variante a
Response response = calculatorWS.isPrimeNumberAsync("78787");
while (!response.isDone()) {
  Thread.sleep(1000);
}
System.out.println("Result: " + response.get().isReturn());

// Variante b
calculatorWS.isPrimeNumberAsync("78787", new AsyncHandler() {
  public void handleResponse(Response response) {
    try {
      System.out.println("Result: " + response.get().isReturn());
    }
    catch (Exception e) {
      e.printStackTrace();
    }
  }
});
Kommentare

Schreibe einen Kommentar

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