Advanced Java Services | Web Services 3 |
Will man selbstenworfene Datentypen verwenden, so muß im SEI die Annotation @SOAPBinding(style = Style.DOCUMENT) verwendet werden. Da dies die Defaulteinstellung ist, kann man diese Annotation auch weglassen, was hier absichtlich nicht geschieht. @SOAPBinding(style = Style.DOCUMENT) wird gebraucht, weil die selbstentworfenen Datentypen in der WSDL-Datei beschrieben werden müssen. In welcher Form diese geschieht legt JSR-101 in der Spezifikation "Java™ API for XML-based RPC JAX-RPC 1.1" fest. Diese Spezifikation (jax_rpc-1_1-mrel-spec.pdf) kann hier angesehen oder/und heruntergeladen werden.
Diese Spezifikation legt u.a. fest, welche primitive Datentypen und welche Klassen aus der API verwendet werden dürfen.
Für selbstentworfenen Klassen gelten folgende Beschränkungen (Spec. 5.4)
Instanzen der Klasse Director sollen den Namen eines (Film-) Regisseurs beinhalten.
package nimdb; import javax.xml.bind.annotation.XmlType; @XmlType public class Director { private String name = ""; public Director() { } /** */ public Director(String name) { this.name = name; } /** */ public String getName() { return name; } /** */ public void setName(String name) { this.name = name; } }
Instanzen der Klasse Movie sollen den Titel eines Films beinhalten.
package nimdb; import javax.xml.bind.annotation.XmlType; @XmlType public class Movie { private String title=""; public Movie() { } /** */ public Movie(String title ) { this.title = title; } /** */ public String getTitle() { return title; } /** */ public void setTitle(String title) { this.title = title; } }
Das Service Endpoint Interface vereinbart zwei Methoden. Die Methode getDirector(Movie movie) soll zu einem Film den Namen des Regisseurs liefern, die Methode getMovies(Director dir) soll eine Liste "aller" Filme liefern, bei denen der übergebene Regisseur Regie geführt hat.
package nimdb; import java.util.List; import javax.jws.WebService; import javax.jws.WebMethod; import javax.jws.soap.SOAPBinding; import javax.jws.soap.SOAPBinding.Style; @WebService @SOAPBinding(style = Style.DOCUMENT) // default public interface NimdbService { @WebMethod public Director getDirector(Movie movie); @WebMethod public List<Movie> getMovies(Director dir); }
Die Implementierung des Interfaces erzeugt on the fly zu zwei Regisseuren eine kleine Liste mit zwei Filmen. Falls ein ungültiger Regisseur oder Film eingegeben wird, geben beide Methoden null zurück.
import java.util.ArrayList; import java.util.List; import javax.jws.WebService; @WebService(endpointInterface = "nimdb.NimdbService", serviceName = "TheNimdbService") public class NimdbServiceImpl implements NimdbService { private static final long serialVersionUID = 1L; public NimdbServiceImpl() { } @Override public List<Movie> getMovies(Director dir) { if (dir==null) return null; if (dir.getName().toLowerCase().equals("fellini")) { List<Movie> list = new ArrayList<>(); list.add(new Movie("schiff der träume")); list.add(new Movie("la strada")); return list; } else if (dir.getName().toLowerCase().equals("bergman")) { List<Movie> list = new ArrayList<>(); list.add(new Movie("sommer mit monika")); list.add(new Movie("wilde erdbeeren")); return list; } return null; } @Override public Director getDirector(Movie movie) { if (movie==null) return null; if (movie.getTitle().toLowerCase().equals("schiff der träume")) return new Director("fellini"); else if (movie.getTitle().toLowerCase().equals("la strada")) return new Director("fellini"); else if (movie.getTitle().toLowerCase().equals("sommer mit monika")) return new Director("bergman"); else if (movie.getTitle().toLowerCase().equals("wilde erdbeeren")) return new Director("bergman"); return null; } }
package nimdb; import java.util.Scanner; import javax.xml.ws.Endpoint; public class NimdbServiceEndpoint { public static void main(String[] args) { String serviceUrl = "http://127.0.0.1:5003/nimdb"; // packagename wird angegeben NimdbService ts = new NimdbServiceImpl(); Endpoint ep=null; try { ep = Endpoint.publish(serviceUrl, ts); //com.sun.xml.internal.ws.transport.http.server.EndpointImpl System.out.println("NimdbService started"); System.out.println("listening on " + serviceUrl); System.out.print("Stop server j/n "); Scanner sc = new Scanner(System.in); String erg = sc.next(); if (erg.toLowerCase().equals("j")) { ep.stop(); System.out.println("server stopped"); } } catch(Exception ex) // BindException { System.out.println(ex); } } }
Obwohl das Projekt eine main()-Klasse besitzt ist es nicht startbar. Erst die erzwungene Compilierung der Klassen über clean und build erzeugt alle class-Dateien, die oben aufgeführt sind. Das reicht allerdings nicht um den Endpoint einzurichten. Dazu muß man weitere Hilfsklassen erzeugen.
Die eigenen Klassen müssen in der WSDL beschrieben werden, damit ein Client diese Datentypen erzeugen kann. Dazu werden Hilfsklassen benötigt, die wsgen erzeugt. wsgen legt diese Klassen in einem Packageunterverzeichnis mit dem Namen jaxws an. Da wsgen mit den class-Dateien arbeitet, mußten diese im vorigen Schritt erzeugt werden. Erst dann kann man wsgen einsetzen.
wsgen wird am besten im class-Verzeichins aufgerufen. In unserem Fall sieht der Aufruf folgendermaßen aus:
...\classes>wsgen -verbose -keep -cp . nimdb.NimdbServiceImpl
Die folgende Tabelle erklärt die Parameter
Parameter | Bedeutung |
-verbose | ermöglicht Konsolmeldungen über die Aktivitäten von wsgen |
-keep | verhindert das Löschen der Quellcodedateien |
. | bedeutet das aktuelle Verzeichnis (hier also classes) |
nimdb.NimdbServiceImpl | der vollständige Name der SIB Service Implementation Bean |
In diesem Beispiel enstehen die Klassen GetDirector, GetDirectorResponse, GetMovie, GetMovieResponse (jeweils .class und .java).
Mit diesen zusätzlichen Dateien ist der oben aufgeführte Serviceendpoint realisierbar.
Der gestartete Endpoint:
import java.io.IOException; import java.net.URL; import javax.xml.ws.Service; import javax.xml.ws.WebServiceException; import javax.xml.namespace.QName; import java.net.MalformedURLException; import java.util.List; import nimdb.NimdbService; import nimdb.Director; import nimdb.Movie; /** Falls der Server nicht bereit ist, gibt es die folgende Fehlermeldung javax.xml.ws.WebServiceException: Failed to access the WSDL at: http://localhost:5003/timeservice?wsdl. It failed with: Got Connection refused: connect while opening stream from http://localhost:5003/timeservice?wsdl. */ public class NimdbServiceClient { public static void main(String[] args) throws IOException { System.out.println("NimdbServiceClient"); try { URL serviceURL = new URL("http://localhost:5003/nimdb?wsdl"); QName qname = new QName("http://nimdb/", "TheNimdbService"); // slash am ende notwendig Service service = Service.create(serviceURL, qname); NimdbService ns = service.getPort(NimdbService.class); //System.out.println(ns.getClass().getName()); Listlist = ns.getMovies(new Director("fellini")); if(list!=null) { System.out.println( ((Movie)list.get(0)).getTitle() ); System.out.println( ((Movie)list.get(1)).getTitle() ); } else { System.out.println("unbekannter Regisseur"); } Movie movie = new Movie("wilde erdbeeren"); Director dir = ns.getDirector(movie); if (dir!=null) { System.out.println(dir.getName()); } else { System.out.println("unbekannter Film"); } } catch(MalformedURLException ex) { System.out.println(ex); } catch(WebServiceException ex) { System.out.println(ex); } } }
Die Ausgabe des Clients: