Rein in die Gelben Seiten

Im dritten Teil des iX-Web-Service-Tutorials geht es darum, die Beschreibung eines Web Service mit dem Java-API JAXR in öffentlichen Verzeichnissen abzulegen und aufzufinden.

vorlesen Druckansicht
Lesezeit: 12 Min.
Von
  • Lars Röwekamp
Inhaltsverzeichnis

Nachdem die letzten beiden Teile des Tutorials zeigten, wie sich ein Java-basierter Web Service mit den XML-Bibliotheken JAX-RPC und JAXM implementieren lässt, liegen die Schwerpunkte diesmal auf der Bekanntmachung eines Web Service innerhalb einer XML-Registry und auf der Suche nach einem Dienst.

Mit der Web Service Description Language (WSDL, www.w3c.org/TR/wsdl/) lassen sich Web Services unabhängig von der zugrunde liegenden Umsetzungssprache beschreiben. Die WSD eines Web Service definiert neben seinen Strukturen und Datentypen vor allem das Mapping zwischen den Parametern und den zugehörigen SOAP-Datentypen sowie das Binding an unterliegende Protokolle.

Sie ist somit ein Vertrag, den Anbieter und Nutzer eines Web Service schließen. Nutzer können den Dienst mit Hilfe der WSD aufrufen, ohne Näheres über seine Implementierung zu wissen. Dass dies auch auf Basis automatisch generierter Clients funktioniert, hat der letzte Teil des Tutorials gezeigt. Dort erzeugte xrpcc die zur Anbindung eines Web Service notwendigen Java-Klassen.

Innerhalb einer WSD lassen sich zwei Abschnitte unterscheiden:

  • Service Implementation Definition;
  • Service Interface Definition.

Zu einem Dienst kann es verschiedene konkrete Implementierungen geben (Abb. 1).

Die Service Implementation Definition beschreibt, wo sich die Implementierung des Dienstes befindet, das heißt über welche protokollspezifische Netzadresse er aufrufbar ist. Die Service Interface Definition dagegen bestimmt, was der Service tut und wie man den Aufruf formatieren muss, damit ihn der Service Provider verarbeitet (s. Abb. 1).

Während ein portType-Element die abstrakte Interface-Definition angibt, definiert binding den konkreten Zugriff auf den Web Service. Ein portType kann wiederum über beliebig viele operation-Elemente verfügen, die mit einer Methodensignatur vergleichbar sind. message-Elemente, die die Parameter einer operation angeben, können wiederum aus einzelnen part-Elementen bestehen. Ein Blick auf die (leicht vereinfachte) WSDL-Datei des CurrencyConverter-Service (Listing 1) verdeutlicht diese Zusammenhänge.

Mehr Infos

Listing 1

Teil einer WSDL-Datei, die den CurrencyConverter-Dienst beschreibt, da er keine komplexen Datentypen benötigt, bleibt das types-Element leer.

<?xml version="1.0" encoding="UTF-8"?>

<definitions name="CurrencyConverter" ... >

<!-- Typen Definition -->
<types/>
<!-- Message Definition -->
<message name="CurrencyConverterRequest ">
<part name="value" type="xsd:float"/>
<part name="fromCurrency" type="xsd:string"/>
<part name="toCurrency" type="xsd:string"/>
</message>
<message name="CurrencyConverterResponse ">
<part name="result" type="xsd:double"/>
</message>

<!-- PortType Definition -->
<portType name="CurrencyConverterPortType">
<operation name="convertCurrency">
<input message="tns:CurrencyConverterRequest"/>
<output message="tns:CurrencyConverterResponse "/>
</operation>
</portType>

<!-Binding Definition -->
<binding name="CurrencyConverterBinding"
type="tns:CurrencyConverter">
<soap:binding style="rpc"
transport="http://schemas.xmlsoap.org/soap/http" />
<operation name="convertCurrency">
<input>
<soap:body use="encoded"
namespace="http://currencyconverter.org/wsdl"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
</input>
<output>
<soap:body use="encoded"
namespace="http://currencyconverter.org/wsdl"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
</output>
<soap:operation soapAction=""/>
</operation>
</binding>

<!-- Service Definition -->
<service name="CurrencyConverterservice">
<port name="CurrencyConverterPort"
binding="tns:CurrencyConverterBinding">
<soap:address location="http://..."/>
</port>
</service>
</definitions>

In diesem Beispiel spielt das Element types keine Rolle. Es dient zur Angabe der selbst definierten Datentypen, die innerhalb der WSDL-Datei zur Anwendung kommen. Doch wie kann eine solche Web Service Description vielen potenziellen Nutzern zur Verfügung gestellt oder von ihnen gefunden werden?

An dieser Stelle kommen XML-Registries ins Spiel, die Gelben Seiten ähneln. Sie können unter anderem Informationen zu einem Unternehmen, seinen Diensten sowie dem Zugriffsmechanismus auf diese enthalten. Registries stellen somit die Infrastruktur für lose gekoppelte Business-2-Business-Interaktionen zur Verfügung.

Derzeit dominieren am Markt zwei XML-Registry-Standards:

  • ebXML, definiert von OASIS und U.N./CEFACT (www.ebxml.org);
  • UDDI (Universal Description, Discovery, and Integration), spezifiziert von einer Gruppe von Unternehmen (www.uddi.org).

Das JAXR-API - Java API for XML Registries - bietet Entwicklern ein Werkzeug zum lesenden und schreibenden Zugriff auf XML-Registries. JAXR abstrahiert von der zugrundeliegenden Registry und beschreibt anhand eines allgemeinen Informationsmodells deren Inhalt und die Metadaten.

Clients können auf verschiedene JAXR-Provider zugreifen, um Informationen aus einer XML-Registry zu erhalten (Abb. 2).

Mit JAXR lassen sich zwei Komponenten erstellen: der Client, der mit dem API auf eine XML-Registry zugreift, und der JAXR-Provider, der einen solchen Zugriff ermöglicht. Zusätzliche Capability Profiles erlauben es, den Funktionsumfang eines JAXR-Providers einzuschränken beziehungsweise zu erweitern. Abbildung 2 verdeutlicht das Zusammenspiel zwischen Client, Provider und Registry.

Beim Umgang mit einer Registry fallen zwei Kernaufgaben an:

  • Registrieren, Ändern und Löschen eines Unternehmens beziehungsweise seiner Dienste (Publishing);
  • Abfragen registrierter Unternehmen beziehungsweise ihrer Dienste (Inquiry).

Da das Eintragen von Diensten in eine XML-Registry in der Regel über ein Web-Interface und nicht automatisiert aus einer Applikation heraus stattfindet, soll es hier lediglich um die Implementierung einer Abfrage via JAXR gehen. Zu diesem Zweck wird die Beispielapplikation myNet-Services um einen ServiceFinder erweitert, mit dem Anwender in verschiedenen XML-Registries nach Unternehmen und deren Diensten suchen können.

Dieser ServiceFinder-Service besteht im Wesentlichen aus zwei Elementen. Zunächst gibt es eine JSP zur Angabe der Suchkriterien. Diese Informationen reicht sie an ein ServiceFinderServlet weiter, das den JAXR-Client darstellt. Die Anzeige der gefundenen Einträge übernimmt schließlich wieder die JSP.

Ein JAXR-Client greift nach folgendem Muster auf die Registry zu:

  1. Erzeugen einer ConnectionFactory;
  2. Herstellen einer Connection;
  3. Zugreifen auf ein RegistryService-Objekt;
  4. Durchsuchen der Registry.

Im letzten Schritt sind verschiedene Kriterien benutzbar, etwa der Name einer Organisation beziehungsweise eines Service oder dessen Binding. Auch eine Suche mit Wildcards ist möglich.

Um eine Connection aus einer ConnectionFactory zu erzeugen, müssen zunächst einige Properties zur Bestimmung der Registry angegeben werden. Listing 2 zeigt einen Ausschnitt aus dem Beispiel-Servlet, das den lesenden und schreibenden Zugriff auf die Registry von IBM realisiert.

Mehr Infos

Listing 2

Zum Erzeugen einer Connection benötigt die ConnectionFactory einige Properties.

...
/* URL zur Abfrage der IBM UDDI Registry */
public final String IBM_UDDI_INQUIRY_URL =
"http://www-3.ibm.com/services/uddi/v2beta/inquiryapi";

/* URL zur Bearbeitung der IBM UDDI Registry - Rechte müssen
vorhanden sein! */
public final String IBM_UDDI_PUBLISHING_URL =
"https://www-3.ibm.com/services/uddi/v2beta/protect/publishapi";

/* Konstante für die Inquiry Property*/
public final String QUERY_MANAGER =
"javax.xml.registry.queryManagerURL";

/* Konstante für die Publishing Property */
public final String LIFE_CYCLE_MANAGER =
"javax.xml.registry.lifeCycleManagerURL";

/* Konstante für den Factory Typ */
public final String FACTORY_CLASS =
"javax.xml.registry.FactoryClass";

/* Konstante für den Factory Typ - UDDI */
public final String FACTORY_CLASS_IMPL =
"com.sun.xml.registry.uddi.ConnectionFactoryImpl";

/* setzen der Properties */
Properties properties = new Properties();
properties.setProperty(QUERY_MANAGER, IBM_UDDI_INQUIRY_URL);
properties.setProperty(LIFE_CYCLE_MANAGER, IBM_UDDI_PUBLISHING_URL);
properties.setProperty(FACTORY_CLASS, FACTORY_CLASS_IMPL);

/* Aufbau der Connection */
ConnectionFactory connectionFactory =
ConnectionFactory.newInstance();
connectionFactory.setProperties(properties);
Connection connection =
connectionFactory.createConnection();

...

Nach dem Aufbau der Verbindung ermöglicht das Connection-Objekt den Zugriff auf ein RegistryService-Objekt, das die eigentliche XML-Registry repräsentiert:

RegistryService regService = connection. getRegistryService();
/* Erzeugen eines Query Managers für Abfragen
und eines Life Cycle Managers für die Manipulation
der Registry- Einträge */
BusinessQueryManager queryManager = regService.getBusinessQueryManager();
BusinessLifeCycleManager lifeCycleManager = regService.getBusinessLifeCycleManager();

Während der BusinessQueryManager die Abfrage einer XML-Registry übernimmt, wickelt der BusinessLifeCycleManager alle Änderungen an der Registry ab.

Im Beispiel soll zunächst lediglich nach Organisationen innerhalb der XML-Registry gesucht werden, in deren Namen sich ein bestimmtes Wort befindet (Listing 3).

Mehr Infos

Listing 3

Verschiedene ‘Qualifier’ ermöglichen das Suchen nach Registry-Einträgen.

...

/* Angabe einer Collection von FindQualifier,
die unter anderem für die
Auswahl und Sortierung der Treffer sorgen. */
Collection findQualifier = new ArrayList();
findQualifier.add(FindQualifier.SORT_BY_NAME_DESC);
findQualifier.add(FindQualifier.CASE_SENSITIVE_MATCH);

/* Organisationsname, nach dem gesucht werden soll */
Collection namePattern = new arrayList();
NamePattern.add(searchName);

/* Starten der Abfrage mit Hilfe des Query Managers */
BulkResponse bulkResponse =
queryManager.findOrganizations(findQualifier,
namePattern,
null,
null,
null,
null);

/* Extrahieren des Ergebnisses in ein Collection Objekt */
Collection organizations = bulkResponse.getCollection();
...

Neben den Parametern findQualifier und namePattern ist vor allem Classification von Interesse. Damit lassen sich Organisationen und deren Dienste nach internationalen Klassifizierungen auffinden, die Unternehmen bei ihrer Registrierung angeben. Gültige Klassifizierungsschemata sind unter anderem

Möchte man zum Beispiel alle WSDL-Spezifikationen innerhalb einer XML-Registry gemäß dem Klassifizierungsschema der UDDI-Spezifikation aufspüren, so lässt sich dies mit dem Code in Listing 4 realisieren.

Mehr Infos

Listing 4

Dieses Programmfragment erfragt alle WSDL-Spezifikationen innerhalb einer XML-Registry.

...

/* Konstante für das UDDI Klassifizierungsschema */
public final String UDDI_ORG_TYPES =
"uddi-org:types";

/* Angabe des zu verwendenden Klassifizierungsschemas */
String searchScheme = UDDI_ORG_TYPES;
ClassificationScheme uddiOrgTypes =
queryManager.findClassificationSchemeByName(null, searchScheme);

/* Erzeugen einer Klassifizierungsinstanz für WSDL-Spezifikationen */
Classification wsdlClassification =
lifeCycleManager.createClassification(uddiOrgTypes,
"wsdlSpec",
"wsdlSpec");

/* Angabe der Klassifikationen, nach denen gesucht werden soll */
Collection classification = new ArrayList();
classification.add(wsdlClassification);

/* Starten der Abfrage mit Hilfe des Query Managers */
BulkResponse bulkResponse =
queryManager.findConcepts(null,
null,
classification,
null,
null);

/* Extrahieren des Ergebnisses in ein Collection-Objekt */
Collection wsdlConcepts = bulkResponse.getCollection();

Als Ergebnis erhält man eine Collection von Concept-Objekten, aus denen zum Beispiel der externe Link zum eigentlichen WSDL-Dokument abfragbar ist oder die Liste aller Organisationen, die diese WSDL-Datei unterstützen. Existiert beispielsweise eine allgemein anerkannte WSDL-Spezifikation für eine bestimmte Art von Dienst, so ließe sich auf diesem Weg nach allen Anbietern dieses Service suchen. Durch weitere Such- und Sortierkriterien könnte man den ‘besten’ Anbieter herausfinden und ihn nutzen. All dies kann zur Laufzeit geschehen.

Als Beispiel führen Theoretiker gern die Suche nach einer Fluglinie an, die einen bestimmten Flug unter Einhaltung einiger Qualitätsanforderungen anbietet. Tatsächlich ist man heute noch einige Schritte von derartigen Anwendungsfällen entfernt. Realistischer dagegen ist ein Szenario, bei dem ein Unternehmen innerhalb einer internen UDDI-Registry verschiedene Anbieter eines Service unter Angabe von Qualifizierungs- und Klassifizierungsmerkmalen registriert. Das versetzt Clients in die Lage, automatisch auf den Ausfall eines Service-Anbieters zu reagieren. Durch die Qualifizierung kann ein Client zur Laufzeit den besten Service Provider bestimmen und dessen Dienst nutzen.

Im erweiteten Web-Service-Stack sind Transaktionen verfügbar, die auf Web Service Coordination beruhen (Abb. 3).

Im August 2002 stellte ein Konsortium verschiedener Unternehmen eine Spezifikation für Web-Service-Transaktionen vor (www-106.ibm.com/developerworks/webservices/library/ws-transpec). Deren Basis bildet die WS-Coordination-Spezifikation, die Wege zur Koordinierung mehrere Web Services festlegt (www-106.ibm.com/developerworks/library/ws-coor). Ihren Kern stellen drei Services zur Aktivierung, Registrierung und Koordination dar, deren Operationen und Nachrichten mittels WSDL definiert werden.

Derzeit sind zwei Arten von Web-Service-Transaktionen definiert:

  • Atomare Transaktionen, die komplett oder gar nicht ausgeführt werden; geeignet für kurze Prozesse.
  • Business Transaktionen, die in der Regel aus mehreren atomaren Transaktionen bestehen; ein flexiblerer Ansatz für langdauernde Prozesse.

Die Spezifikationen lassen sich um beliebige Typen erweitern. Auch die Kombination der beiden Transaktionsarten ist erlaubt.

Grundidee der neuen Spezifikationen ist die Anmeldung mehrerer Web Services als Teilnehmer einer ‘Koordination’ - also zum Beispiel einer der oben genannten Transaktionsarten - beim Coordination Service. Dieser übernimmt die Kontrolle der gesamten Aktivität. Zur Unterstützung dient dabei ein für jede Aufgabe erzeugter Coordination Context.

Ein wesentlicher Vorteil von Web Services liegt theoretisch in ihrer Interoperabilität. Durch die strikte Trennung von Definition und Implementierung können die Implementierung und Nutzung von Diensten in einer beliebigen Programmiersprache erfolgen. Ein beliebtes Beispiel ist an dieser Stelle die Verbindung von .Net- und Java-basierten Systemen [4].

Allerdings zeigt die praktische Arbeit mit Web Services, dass dies bei einer mittlerweile schier unüberschaubaren Anzahl von SOAP-Frameworks und -Toolkits eher Wunsch als Wirklichkeit ist. Das liegt unter anderem an der SOAP-Spezifikation, die manches offen lässt und andernorts Interpretationsspielraum bietet.

Generell klappt die Zusammenarbeit gut, wenn man sich an die in www.w3c.org/TR/soap/ spezifizierten Standarddatentypen hält. Beginnt man allerdings mit der Einbindung komplexer, selbstdefinierter Datentypen, sieht die Welt schon anders aus.

Um sicher zu gehen, müssen Entwickler reichlich testen und recherchieren. In der jüngsten Vergangenheit haben sich mehrere Webseiten mit Tücken der Interoperabilität befasst und Online-Labore eingerichtet, die Web Services und WSDs auf Allgemeingültigkeit prüfen.

Einfache echo-Nachrichten benutzt die SOAPBuilder-Initiative, um die Kompatibilität verschiedener Implementierungen von Web Services zu testen (Abb. 4).

So bietet zum Beispiel xMethods (www.xmethods.net) einen WSDL-Analyser, um eine gegebene WSD auf verschiedene Aspekte der Interoperabilität zu prüfen. Einen Schritt weiter geht die von mehreren Unternehmen gegründete SOAPBuilder-Initiative. Unter www.whitemesa.com/interop.htm findet sich ein ‘Interoperability Lab’, das für SOAP-Frameworks und Toolkits im Detail beleuchtet, wann es zu Schwierigkeiten kommen kann. Die SOAPBuilder-Initiative definiert verschiedene Testszenarien, deren Ergebnisse auf der Webseite eingesehen werden können. Mittels einfacher Tests (s. Abb. 4) lassen sich dort die Toolkits auf Kompatibilität der verschiedenen Datentypen testen.

Ebenfalls eine informative Quelle für alle Web-Service-Entwickler ist www.soapclient.com. Neben der Interoperabilität erläutert diese Seite etliche andere Themen rund um SOAP und stellt eine Reihe brauchbarer Tools bereit, etwa einen UDDI-Browser.

Das Tutorial hat gezeigt, wie sich die verschiedenen Aspekte der Java-basierten Implementierung und Anbindung von Web Services mit dem Web Service Development Pack von Sun realisieren lassen. Sein Einsatz bedeutet in der Regel anfänglich einen höheren Aufwand verglichen mit anderen Frameworks (etwa dem Web-Service-Projekt Axis der Apache Group). Demgegenüber steht der Vorteil der erhöhten Flexibilität sowie der damit gewonnenen Unabhängigkeit von öffentlichen oder kommerziellen Framework-Anbietern.

Ob sich Web Services in der Zukunft - Java hin, .Net her - am Markt tatsächlich in der gewünschten Form etablieren können, hängt nicht zuletzt von der Beseitigung noch bestehender Schwierigkeiten ab. Wie dieser Artikel gezeigt hat, existieren vor allen in essenziellen Bereichen wie Transaktionen, Sicherheit und der vielbeschworenen Interoperabilität noch etliche ungeklärte Punkte.

Lars Röwekamp
ist als IT-Berater mit den Schwerpunkten Neue Technologien und OO/Java für seine Firma OpenKnowledge GmbH tätig.

[1] Stefan Edlich; B2B-Standardisierung; Weiß, Gelb, Grün; UDDI: Geschäftsdaten bereitstellen und nutzen; iX 2/2001, S. 133

[2] Lars Röwekamp; Web-Programmierung; Dienste leisten; Java Web Service Tutorial - Teil 1: Grundlagen; iX 9/2002, S. 121

[3] Lars Röwekamp; Web-Programmierung; Nehmen und geben; Java Web Service Tutorial - Teil 2: Selber schreiben; iX 10/2002, S. 134

[4] Christian Salzmann, Gregor Schrägle; Web Services; Eingeseift; EJB und .NET mit SOAP koppeln; iX 7/2002, S. 132

Mehr Infos

iX-TRACT

  • XML-Registries dienen zum Speichern und Auffinden von Web Services. Das Java-API JAXR erlaubt den programmatischen Zugriff auf Registries.
  • Da die Soap-Spezifikation Lücken und Unklarheiten enthält, läßt sich die Interoperabilität von Web Services nur durch intensives Testen gewährleisten.

Zip-Datei: webservice-tutorial-III (2,4 MB)

Mehr Infos

Das iX-Tutorial ‘Web Services’

Teil 1: Grundlagen, Einführung in service-orientierte Strukturen, einfaches Beispiel

Teil 2: Unterschiedliche Ausprägungen von Web Services (RPC, Messaging, SOAP-Aufrufe)

Teil 3: Benutzung der Registry für Anbieter und Kunden, Interoperabilität von Diensten, Sicherheit und Transaktionen

(ck)