|
Diplomarbeit
13. September 2002
|
Inhaltsverzeichnis
1 EinleitungAnhang
A Quellcode
WebServices werden von der Industrie als der neue Standard für die plattform- und sprachenunabhängige Abbildung von Geschäftsprozessen und Applikationen auf Basis verteilter Prozesslogik angepriesen. Die noch relativ junge Architektur setzt sich aus einer Vielzahl kooperierender, aufeinander aufbauender und auch konkurrierender Technologien zusammen. Die Spezifizierung und Implementierung dieser Technologien führte auf grundlegenden Ebenen, wie Kommunikation und Beschreibung, bereits zur Standardisierung. Höhere Ebenen, wie z.B. Sicherheit oder Orchestrierung, befinden sich derzeit in der Konsolidierungsphase, bei der firmenpolitische Interessen keine unerhebliche Rolle spielen.
Seit dem Jahr 2001 werden WebServices von Unternehmen aus der IT-Branche als der nächste technologische Schritt für das Internet propagiert. In diesem Zusammenhang wurden eine Unzahl von Spezifikationen verschiedenster Firmen und Organisationen veröffentlicht. Eine Standardisierung findet jedoch nur in kleinen Schritten statt. Deshalb verwundert es kaum, dass der Begriff "WebService" in erster Linie Markteingzwecken dient, aber keiner einheitlichen Definition unterliegt. Die Versuche der einzelnen Unternehmen WebServices zu definieren, fallen daher relativ unterschiedlich aus:
Aus der Sicht der Geschäftswelt sind WebServices der Weg zur Integration von Applikationen und deren Funktionalitäten. Einzubindende Funktionen können sowohl innerhalb der eigenen Firma als auch bei externen Geschäftspartnern lokalisiert sein. So könnte z.B. ein Reisebüro mit Hilfe von Webservices individuelle Angebote ohne Wartezeit erstellen. Leistungen, die das Reisebüro nicht selbst im Programm hat, wie Autovermietung, werden zum Zeitpunkt der Anfrage über weltweit zugängliche WebService-Datenbanken aufgespürt und integriert.
Aus technischer Sicht ist ein WebService eine Sammlung zusammengehöriger Operationen, die über ein Netzwerk zugänglich sind. Dieses Konzept ist jedoch nicht neu und wurde schon mehrmals in ähnlicher Weise verwirklicht (CORBA, COM, RMI). Das Equivalent zu IDL (Interface Definition Language) findet man beispielsweise bei WebServices in Form der Beschreibungssprache WSDL (Web Service Description Language) wieder. WebServices sind daher vielmehr als eine Weiterführung der bisherigen Technologien zu verstehen. Das wirklich Neue dabei stellt die Verwendung offener Standards dar, so dass ein plattform- und sprachenübergreifender Informationsaustausch möglich wird. Als Basis aller WebService-Technologien dient XML, auf dessen Grundlage verschiedene Protokolle, wie z.B. SOAP (Kommunikation) oder WSDL (WebService-Beschreibung) entwickelt wurden. Weiterhin müssen Mechanismen für die Veröffentlichung und Suche als integraler Bestandteil des WebService-Konzepts erwähnt werden.
Ein naheliegender Trugschluss soll von vorne herein ausgeräumt werden. Die WebService-Technologie suggeriert durch ihren Namen eine Verwendung im WWW (World Wide Web). Ein WebService kann jedoch an jeder beliebigen Stelle eines Netzwerkes -- im Inter- oder Intranet -- existent sein. Sogar ein einfacher Methodenaufruf innerhalb eines Systemprozesses kann schon als WebService verstanden werden. Mit dem auf Browser und HTML fokusierten WWW haben WebServices also nur bedingt zu tun, wenngleich im momentanen Anfangsstadium die WebServices genau in diesem Umfeld realisiert werden.
Viele derzeit verwendete Systeme in der Geschäftswelt basieren auf fest verknüpften Applikationen. Der Nachteil dieses Ansatzes liegt darin, dass auf Änderungen oder Fehler nur sehr unflexibel reagiert werden kann. Die sogenannte Service-Orientierte Architektur (SOA) versucht diesem Problem entgegenzuwirken, indem die festen Bindungen durch lose Kopplungen ersetzt werden. SOA wurde bereits Anfang 2000 von HP als Konzept für ein dynamisches Geschäftsmodell im Internet entwickelt. Mit dem proprietären e-speak scheiterte HP jedoch, SOA als Produkt zu verwirklichen. Mit der auf offenen Standards basierenden WebService-Technologie steht nun eine vielversprechende Neuimplementierung dieser Architektur zur Verfügung.
Viele größere Unternehmen, die in die Entwicklung von WebService-Spezifikationen involviert sind, propagieren unterschiedliche Vorstellungen zum Aufbau des Technologie-Stacks. Mit Vorliebe werden Spezifikationen aus eigener Herstellung integriert und zum Standard erklärt. Folgende Auflistung versucht einen möglichst allgemeingültigen Aufbau des Technologie-Stacks wiederzugeben und wo nötig, auf Besonderheiten hinzuweisen. Während die drei untersten Schichten schon als fester Bestandteil des Stacks betrachtet werden können, ist ein Konsens in Bezug auf die höheren Schichten noch nicht erkennbar.
WSDL (Web Service Description Language) ist ein XML Format für die genaue Beschreibung wie ein WebService aufzurufen ist. Ariba, IBM und Microsoft waren maßgeblich an der Entwicklung von WSDL beteiligt, das dem W3C im September 2000 zur Standardisierung übergeben wurde. Seit März 2001 liegt WSDL in der Version 1.1 beim W3C vor. Während diese Diplomarbeit entstand, wurde am 9. Juli 2002 der erste "Working Draft" zu WSDL 1.2 veröffentlicht. Der Entwurf eignet sich jedoch noch nicht um die endgültige Fassung beurteilen zu können, da er größtenteils nur Vorschläge für Änderungen enthält. Deshalb wird im folgenden WSDL in der Version 1.1 behandelt und auf mögliche Änderungen in Version 1.2 nur am Rande verwiesen. Eine WSDL ist ein XML-Dokument, das zur WSDL Schema-Definition konform ist. Ein WSDL-Dokument ist jedoch nicht eine allumfassende Beschreibung eines WebService, sondern definiert lediglich eine Schnittstelle mit der ein Low-Level-Zugriff auf den WebService erfolgen kann. WSDL hat dabei folgende Fragen zu klären:
Das WSDL Informations-Modell separiert abstrakte Spezifikationen und konkrete Implementationen. Dies wird an der Aufteilung in Service-Schnittstellendefinition (abstrakte Schnittstelle) und Service-Implementationsdefinition (konkreter Endpunkt) deutlich. Die Beschreibung der WebService-Fähigkeiten (Methoden) ist die abstrakte Schnittstellenspezifikation (
<portType>-Element). Ein Binding-Mechanismus (<binding>-Element) verbindet die Netzwerkadresse mit konkreten Nachrichtenprotokollen, Datenformaten und darunterliegenden Kommunikationsprotokollen. Mit der Assoziation des Bindings mit einer Adresse, welche den Zugriff auf die Implementation wiedergibt, wird aus einem abstrakten ein konkreter Endpunkt (<port>-Element).
Erklärung der wichtigsten Elemente eines WSDL-Dokuments:
<definition>
<message>
<message> kann in <part>-Elemente zerlegt werden, die die Daten bzw. Datentypen einer Nachricht beschreiben.<operation>
<portType>
<operation>-Element eine abstrakte Methode definiert.<binding>
<operation> und <message> innerhalb eines <portType>.<port>
<service>
<port>-Elemente. Die <port>-Elemente kommunizieren jedoch nicht miteinander sondern ermöglichen dem Benutzer eine Auswahl derselben.<types>
<part>-Elementen referentiell angesprochen werden können.<portType> (mit Details aus <message> und <types>) klärt also das WAS (angebotene Methoden). Das <binding>-Element beschreibt das WIE (Protokolle, Datenformate) und das <port>-Element das WO (URL).
Eine detailierte Erläuterung, aufgeteilt in abstrakte und konkrete Elemente, erfolgt nun an Hand eines Beispiels. Dazu wurde folgendes WSDL-Dokument gewählt, das einen WebService für eine Preisauskunft in einem Warenhaus darstellt. Der WebService ermöglicht mit Hilfe der Operation priceCheck den Preis eines Artikels und dessen lieferbare Stückzahl anhand einer Artikelnummer (sku) zu ermitteln.
<?xml version="1.0"?>
<definitions name="PriceCheck"
targetNamespace="http://www.pixel.de/services/PriceCheck"
xmlns:pc="http://www.pixel.de/services/PriceCheck"
xmlns:avail="http://www.pixel.de/ns/availability"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns="http://schemas.xmlsoap.org/wsdl/">
<!--=== Definition der abstrakten Service-Schnittstelle ===-->
<!-- Definition spezieller Datentypen -->
<types>
<xsd:schema targetNamespace="http://www.pixel.de/ns/availability"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:complexType name="availabilityType">
<xsd:sequence>
<xsd:element name="sku" type="xsd:string"/>
<xsd:element name="price" type="xsd:double"/>
<xsd:element name="quantityAvailable" type="xsd:integer"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
</types>
<!-- Definition der Nachrichten -->
<!-- PriceCheckRequest beinhaltet die Artikelnummer (sku) -->
<message name="PriceCheckRequest">
<part name="sku" type="xsd:string"/>
</message>
<!-- PriceCheckResponse beinhaltet eine Struktur, -->
<!-- die unter types definiert wurde -->
<message name="PriceCheckResponse">
<part name="result" type="avail:availabilityType"/>
</message>
<!-- portType definiert, -->
<!-- WAS ein WebService macht (angebotene Methoden) -->
<portType name="PriceCheckPortType">
<operation name="checkPrice">
<input message="pc:PriceCheckRequest"/>
<output message="pc:PriceCheckResponse"/>
</operation>
</portType>
<!--=== Implementierung der abstrakten Service-Schnittstelle ===-->
<!-- binding definiert, -->
<!-- WIE auf einen WebService zugegriffen werden kann -->
<!-- (Daten-Formate und Protokolle fuer die Kommunikation) -->
<binding name="PriceCheckSOAPBinding" type="pc:PriceCheckPortType">
<soap:binding style="rpc"
transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="checkPrice">
<soap:operation soapAction=""/>
<input>
<soap:body use="encoded"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="http://www.pixel.de/services/PriceCheck"/>
</input>
<output>
<soap:body use="encoded"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="http://www.pixel.de/services/PriceCheck"/>
</output>
</operation>
</binding>
<service name="PriceCheckService">
<!-- port definiert, -->
<!-- WO ein WebService zu finden ist -->
<port name="PriceCheck" binding="pc:PriceCheckSOAPBinding">
<soap:address
location="http://localhost:8080/axis/services/PriceCheck"/>
</port>
</service>
</definitions>
Ausgehend vom
<portType>-Element kann die Funktionsweise einer WSDL leicht verstanden werden. <portType> beschreibt die Schnittstelle des WebService und gibt einen Überblick über das, WAS der WebService macht.
Obwohl die Spezifikation keine oder mehrere <portType>-Definitionen erlaubt, enthält ein WSDL-Dokument typischerweise genau ein <portType>-Element. Diese Konvention separiert WebService-Schnittstellen in verschiedene Dokumente und fördert dadurch die Wiederverwendbarkeit.
<portType name="PriceCheckPortType">
<operation name="checkPrice">
<input message="pc:PriceCheckRequest"/>
<output message="pc:PriceCheckResponse"/>
</operation>
</portType>
Das <portType>-Element definiert hier also die abstrakte Operation checkPrice inklusive Übergabe- und Rückgabeparameter.
<operation>-Elemente innerhalb eines <portType> definieren die Syntax für den Aufruf der Methoden. Jedes <operation>-Element deklariert den Namen der Methode und deren Übergabe- bzw. Rückgabe-Parameter (<input> bzw. <output>). Über die message-Attribute wird zu den entsprechenden <message>-Elementen verwiesen, die Anzahl und Datentyp der Parameter genau spezifizieren.
<message name="PriceCheckRequest">
<part name="sku" type="xsd:string"/>
</message>
<message name="PriceCheckResponse">
<part name="result" type="avail:availabilityType"/>
</message>
Die Auslagerung der <message>-Elemente ermöglicht das Überladen einer Operation. Man könnte dadurch z.B. zwei <operation>-Elemente mit Namen checkPrice definieren die sich nur in ihrem <input>-Element unterscheiden. Es bestehen Überlegungen diese Funktionalität in der Version 1.2 der WSDL-Spezifikation wieder zu entfernen.
Ein
<operation>-Element kann Kombinationen der Elemente <input>, <output> und <fault> enthalten. Die WSDL-Spezifikation definiert vier verschiedene Kombinationen dieser Elemente als sogenannte Transmission Primitives:
input- und eine output-Nachricht. fault-Nachrichten sind optional und können für auftretende Fehler verwendet werden.
Request-Response Nachrichten erfüllen verschiedene Aufgaben. Zum einen besitzen sie einen informellen Charakter, wobei Informationen über ein bestimmtes Objekt des WebService geliefert werden. Zum anderen ist auch ein zustandsändernder Charakter möglich, wobei die Übergabeparameter den Status ändern und der Rückgabewert den neuen Status bzw. den Erfolg des Aufrufs dokumentieren. Die Operation checkPrice aus dem Beispiel kann also dem Request-Response-Schema mit informellem Charakter zugeordnet werden.
<fault>-Elemente müssen zusätzlich zum message-Attribut ein eindeutiges name-Attribut innerhalb des Operationsblocks besitzen.
<portType name="PriceCheckPortType">
<operation name="checkPrice">
<input message="pc:PriceCheckRequest"/>
<output message="pc:PriceCheckResponse"/>
<fault message="PriceCheckSkuError"
name="PriceCheckSkuError"/>
</operation>
</portType>
<output>-Element und daher auch kein <fault>-Element. Oneway wird benutzt um den Status des Service Providers zu ändern und lässt sich mit einer herkömmlichen Methode mit Rückgabewert void vergleichen. Eine Oneway-Operation ist also nur sinnvoll, wenn keine Informationen als Rückgabewert benötigt werden. Anhand einer Abbruch-Operation kann dies verdeutlicht werden:
<operation name="cancellation">
<input message="StockAvailableCancellation"/>
</operation>
Im Allgemeinen kommunizieren WebServices per SOAP-over-HTTP. Da es auf Ebene des HTTP-Protokolls keine Oneway-Operationen gibt, werden diese durch eine normale HTTP-Request-Response-Kommunikation simuliert, wobei das Response-Paket keine SOAP-Nachricht enthält.
<operation name="notification">
<output message="StockAvailableNotification"/>
</operation>
Bevor der Service Provider eine Mitteilung verschicken kann, muss dieser den Empfänger jedoch kennen. Die WSDL-Spezifikation geht auf diese Problematik jedoch in keiner Weise ein. Eine Möglichkeit besteht darin, zuvor eine Registrierung durchzuführen, indem die Zieladresse an den Service Provider in einer Nachricht übergeben wird.
Es ist dabei zwingend notwendig, dass die Registrierung vor dem Versenden einer Mitteilung stattfindet. WSDL bietet jedoch keine Möglichkeit zur Flusskontrolle an. Als Behelfslösung innerhalb von WSDL kann hier eine Dokumentation im <portType>-Element dienen:
<documentation>
Note:
the requestor must invoke the registration operation first.
</documentation>
Für eine vollautomatische Verarbeitung ist diese Verfahrensweise gänzlich unbrauchbar. Zur Lösung dieser Probleme gibt es Ansätze, wie z.B. WSFL oder BMPL, die sich momentan in der Entwicklung befinden.
<output>), zusätzlich wird jedoch eine Antwort (<input>) vom Requestor erwartet.
<portType name="someName">
<operation name="exampleSolicitResponse">
<output message="pushThis"/>
<input message="responseToPush"/>
<fault message="faultPushedToRequestor"
name="someFaultName"/>
</operation>
</portType>
Tritt ein bestimmtes Ereigniss beim Service Provider auf, werden <output> und <fault> zum Service Requestor geschickt. Hier tritt das gleiche Problem wie schon bei Notification auf -- nämlich wohin der Service Provider die Solicit-Nachricht senden soll. Es gelten die gleichen Lösungsansätze wie bei Notification.
Ein kleines aber wichtiges Detail im Vergleich von Solicit-Response und Request-Response besteht in der Reihenfolge von <output> und <input>, die im <operation>-Element auftauchen. Dies ist nämlich das einzige Unterscheidungsmerkmal der beiden Verfahren. Um hier Klarheit zu schaffen sollte darauf geachtet werden, message-Attribute selbsterklärend zu benennen (Request/Response bzw. Solicit/Response).
Notification und Solicit-Response lassen auf Grund ihrer unvollständigen Spezifizierung in WSDL Version 1.1 unterschiedliche Interpretationen zu, was zu einer relativ seltenen Anwendung in der Praxis führte. Für WSDL 1.2 wird deshalb erwogen Notification und Solicit-Response durch einen Ereignis-Mechanismus zu ersetzen.
Die Binding-Sektion spezifiziert Protokoll, Serialisation und Encoding für die Übertragung. Während die
<type>-, <message>- und <portType>-Elemente die Daten im Abstrakten behandeln, werden im <binding> die physikalischen Details für die Datenübertragung festgelegt. <binding> konkretisiert also die Abstraktionen der drei genannten Elemente.
Die Trennung der Binding-Spezifikationen von Daten- und Nachrichtendeklarationen ermöglicht verschiedenen Anbietern, die den gleiche Service-Funktionalität anbieten wollen, eine Standardisierung mit Hilfe des <portType>-Elements. Jeder Anbieter kann die in <portType> abstrakt definierten Operationen über eigene Bindings anbieten. Banken können z.B. standardisierte Operationen für die Kontoabwicklung anbieten, wobei jedes Bankinstitut das darunterliegende Protokoll, Serialisierung und Encoding selbst bestimmen kann. Somit wird also die Wiederverwendbarkeit gefördert und eine Anpassung an die bestehende Infrastruktur vereinfacht.
Der Service-Benutzer weiß anhand der Bindings wie die Datenkommunikation auf Protokollebene stattfinden muss.
<binding name="PriceCheckSOAPBinding" type="pc:PriceCheckPortType">
<soap:binding style="rpc"
transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="checkPrice">
<soap:operation soapAction=""/>
<input>
<soap:body use="encoded"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="http://www.pixel.de/services/PriceCheck"/>
</input>
<output>
<soap:body use="encoded"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="http://www.pixel.de/services/PriceCheck"/>
</output>
</operation>
</binding>
Ein Binding spezifiziert genau ein Transportprotokoll (hier SOAP), jedoch keine Addressinformationen. Der Name des <binding>-Elements (PriceCheckSOAPBinding) muss eindeutig unter den Bindings des WSDL-Dokuments sein. Bereits aus dem Namen lassen sich Informationen extrahieren, denn konventionell wird dieser aus dem <port>-Namen, dem Namen des Protokolls und dem Wort "Binding" zusammengesetzt.
Mit dem type-Attribut (pc:PriceCheckPortType) wird der Bezug durch Namensreferenzierung zum <portType> hergestellt.
WSDL besitzt einen Mechanismus, der es z.B. erlaubt ein
<binding>-Element mit Elementen eines anderen Namensraumes zu erweitern (<soap:...>). Dadurch ist es möglich WSDL-Bindings mit beliebigen Protokollen und Datenformaten zu verwenden. WSDL 1.1 behandelt dazu die Binding-Erweiterungen SOAP 1.1/HTTP, HTTP (GET/POST) und SOAP mit MIME-Attachments. Hat man sich also auf ein bestimmtes Protokoll festgelegt, können die entsprechenden Konventionen der WSDL-Spezifikation benutzt und gemäß seinen Bedürfnissen angepasst werden. In den hier beschriebenen Beispielen wird SOAP (gekapselt in HTTP-Pakete) als Binding-Erweiterung gewählt, da es derzeit am meisten propagiert und auch verwendet wird.<soap:binding> legt fest, dass für die Kommunikation das SOAP-Protokoll mit dessen Elementen Envelope, Header und Body benutzt wird.
<soap:binding style="rpc"
transport="http://schemas.xmlsoap.org/soap/http"/>
Das style-Attribut besagt hier, dass alle Operationen den Konventionen eines entfernten Methodenaufrufs (RPC = Remote Procedure Call) gemäß der SOAP-Spezifikation folgen. Sofern das style-Attribut nicht explizit überschrieben wird hat es für alle Kind-Elemente Gültigkeit. Der andere mögliche Wert für dieses Attribut ist document. Bei document werden alle im SOAP-Body enthaltenen Daten als reines XML übertragen. Im Gegensatz zum entfernten Methodenaufruf wird hier also dokumentenzentriert gearbeitet, was eine flachere Verschachtelungsstruktur zur Folge hat.
transport-Attribut zeigt das Transportprotokoll für die SOAP-Nachrichten an. Die URI http://schemas.xmlsoap.org/soap/http entspricht dem HTTP-Binding in der SOAP Spezifikation. URIs für SMTP, FTP usw. sind ebenfalls möglich.
<soap:operation>-Element liefert Informationen über die Operation als Ganzes.
<soap:operation
soapAction=
"http://www.pixel.de/StockAvailableNotification/registration"/>
Das soapAction-Attribut spezifiziert den SOAPAction-Eintrag im HTTP-Header. Die verwendete URI sollte absoluten Charakter besitzen um eine eindeutige Zuordnung einer Operation zu erlauben. Für andere Protokolle als HTTP darf das soapAction-Attribut nicht verwendet werden.
Optional ist ein style-Attribut möglich um von dem im <soap:binding> definierten Standard-style abzuweichen (rpc oder document).
<soap:body> beschreibt, wie die empfangenen (<input>) bzw. gesendeten (<output>) Nachrichten in der SOAP-Nachricht erscheinen.
<input>
<soap:body use="encoded"
namespace="http://www.pixel.de/services/PriceCheck"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
</input>
Attribute des <soap:body>-Elements:
use
use-Attribut kann die Werte encoded bzw. literal annehmen. literal bedeutet, dass die resultierende SOAP-Nachricht die Daten genau in dem Format enthält, wie es in den abstrakten WSDL-Elementen (<types>, <message> und <portType>) spezifiziert wurde. Wird der Wert encoded benutzt, verweist das Attribut encodingStyle auf die genaue Kodierungsweise der Daten.namespace
encodingStyle
http://schemas.xmlsoap.org/soap/encoding
parts
parts enthält die Namen der <part>-Elemente einer <message>, die innerhalb des SOAP-Bodies auftauchen. Bei Weglassen des Attributs werden alle <part>-Elemente der entsprechenden <message> genutzt.<soap:header>, <soap:headerfault>, <soap:fault>).
<soap:fault>-Element beschreibt wie ein <fault>-Element einer Operation nach SOAP übertragen wird. Für Fehler, die sich auf den Header beziehen, verlangt die SOAP-Spezifikation, dass diese auch im Header zurückgegeben werden müssen (<soap:headerfault>).
Die einzige Aufgabe die ein
<port>-Element erfüllt, ist die Assoziation genau einer Netzwerkadresse des Endpunktes, der den WebService anbietet, mit einem bestimmten Binding-Element.
<port name="PriceCheck" binding="pc:PriceCheckSOAPBinding">
<soap:address
location="http://www.pixel.de/services/PriceCheck"/>
</port>
Somit wird festgelegt wohin eine SOAP-Nachricht geschickt werden muss, wenn die priceCheck-Operation über SOAP aufgerufen wird. Zu beachten ist, dass auch hier die SOAP-Erweiterung in Form des <soap:adress>-Elements zum Tragen kommt. Dies ist jedoch das einzige Vorkommen außerhalb eines <Binding>-Elements.
Der Zweck eines
<service>-Elements ist das Gruppieren von verwandten <port>-Elementen. Obwohl ein WSDL-Dokument beliebig viele <service>-Elemente enthalten kann, wird die Anzahl in der Regel auf ein Element beschränkt.
<service name="PriceCheckService">
<port name="PriceCheck" binding="pc:PriceCheckSOAPBinding">
<soap:address
location="http://www.pixel.de/services/PriceCheck"/>
</port>
</service>
Es gibt verschiedene Aspekte, warum und wie man die Gruppierung vornehmen sollte. Zum einen kann es nützlich sein, verwandte, aber verschiedene <portType>-Elemente zu gruppieren.
Zum anderen können <port>-Elemente zusammengefasst werden, die sich auf den gleichen <portType> beziehen, aber verschiedene Protokolle benutzen (Binding). Beispielsweise könnte also der priceCheck-<portType> auf zwei Arten implementiert werden (SOAP-over-HTTP und SOAP-over-SMTP), wobei die dazugehörigen <port>-Elemente dann die Netzwerkadresse für das jeweilige Protokoll enthalten würden.
Wie bereits erwähnt, wurde am 9. Juli 2002 der erste Arbeitsentwurf für WSDL 1.2 vorgestellt. Folgende Verbesserungen gegenüber Version 1.1 soll die erneuerte Spezifikation bieten:
WSDL genießt, ebenso wie SOAP, große Akzeptanz als eine der Basiskomponenten von WebServices. Durch die Aufteilung eines WSDL-Dokuments in abstrakter Schnittstellendefinition des WebService und der konkreten Implementierung in Form der verwendeten Übertragungsprotokolle (SAOP-over-HTTP, SMTP usw.) ist eine Erweiterung um andere Protokolle relativ leicht zu realisieren. Anfängliche Beschwerden seitens der Entwickler über die hohe Komplexität von WSDL sind auf Grund der automatisierten Generierung, die heute praktisch jedes WebService-Entwicklungswerkzeug beherrscht, verstummt.
|
Bei AXIS steht immer die Nachricht und ihre Verarbeitung im Vordergrund. Für jede eingehende Anfrage wird eine Instanz der Klasse
MessageContext erzeugt, über das auf Request- und Response-Nachricht zugegriffen werden kann. Vor und nach dem eigentlichen Aufruf, der als WebService angebotenen Anwendung, durchläuft der MessageContext eine Reihe sogenannter Handler. Jeder Handler ist mit einem bestimmten Verarbeitungsmuster ausgestattet und kann beispielsweise für eine Authentifizierung des Service-Benutzers sorgen.
Die interne Struktur von AXIS teilt sich in mehrere kooperierende Subsysteme und dem eigentlichen Kern, der im folgenden Abschnitt erläutert wird.
Die AXIS-Engine ist der Haupteintrittspunkt für das Modell der Nachrichtenverarbeitung und sorgt als Koordinator der SOAP-Nachrichten für deren Fluss durch die entsprechenden Komponenten (Handler und Chains). Die abstrakte Klasse
AxisEngine besitzt für Client und Server je eine konkrete Subklasse, die auf verschiedene Art und Weise initialisiert werden:
AxisServer
MessageContext-Objekt, woraufhin die Prozesslogik der AXIS-Engine gestartet wird.AxisClient
MessageContext-Objekt und übergibt ihn der AXIS-Engine. AXIS liefert dafür entsprechende Code-Konstrukte.
Ein Handler stellt die Basiskomponente für die Verarbeitung von Nachrichten in AXIS dar. Sogar die AXIS-Engine selbst ist ein Handler. Ein Chain beinhaltet eine bestimmte Anzahl von Handlern. Ein Chain ist selbst jedoch auch ein Handler und ermöglicht somit Gruppierungen und Verschachtelungen im Ablaufsystem. Wenn die zentrale Prozesslogik läuft, werden alle Handler in einer vorher definierten Reihenfolge durchlaufen. Jedem Handler wird bei Aufruf der aktuelle
MessageContext zur Verfügung gestellt, der für das jeweilige Verarbeitungsmuster des Handler genutzt wird. Die genaue Abfolge der Handler wird durch zwei Faktoren bestimmt. Zum einen wird unterschieden ob die AXIS-Engine als Client oder Server gestartet wurde und zum anderen kann die Ablaufreihenfolge konfiguriert werden, z.B. von außen über WSDD-Dateien (Web Service Deployment Descriptor).
Durch das Modul-Prinzip der Handler wird Erweiterbarkeit und Wiederverwendbarkeit gefördert. Soll ein WebService beispielsweise zusätzliche Logging-Funktionen erhalten, so muss diese Funktionalität nicht im Quellcode des Programms selbst implementiert werden. Es muss lediglich ein Handler programmiert werden, der in den entsprechenden Chain eingehängt wird. Da die eigentliche Anwendung nicht zwingend von der Existenz bzw. Funktion eines Handler wissen muss, können allgemeingültige Handler WebServices in beliebiger Kombination erweitern.
| |
![]() |
|
Abb.: Ein Chain besitzt eine beliebige Anzahl von Handler, implementiert aber auch selbst ein Handler-Interface
|
| |
Für jede Aktivierung der AXIS-Engine, sei es nun im Client-Modus oder als Anfrage im Server-Modus, wird eine Instanz der Klasse
MessageContext erzeugt. Der MessageContext wird innerhalb einer AXIS-Engine von Handler zu Handler durchgereicht und bietet Methoden zur Information und Manipulation in Bezug auf die enthaltenen Nachrichten und deren Umgebung. Der MessageContext setzt sich aus folgenden Bestandteilen zusammen:
Message, welche von javax.xml.soap.SOAPMessage abgeleitet wurde. Nicht zu jedem Zeitpunkt müssen beide Nachrichten vorhanden sein. So wird die Response-Nachricht üblicherweise erst nach dem Aufruf der eigentlichen Ziel-Applikation hinzugefügt. Wie die Abbildung messagecontext zeigt, besteht jedes Message-Objekt aus einem SOAP-Teil und einem Attachment.
Die nachfolgende Abbildung zeigt den serverseitigen Nachrichtenweg. Jeder Zylinder entspricht einem Handler. Ein Handler, der wiederum Handler enthält, repräsentiert einen Chain. AXIS beinhaltet auf oberster Ebene drei verschiedene Bereiche im Nachrichtenflusssystem:
AxisEngine in Form von drei fest implementierten Handler bzw. Chains realisiert.
Nachrichten werden protokollspezifisch vom Transport-Listener empfangen. Angenommen dieser wird als HTTP-Servlet implementiert, so wird der Body (SOAP-Nachricht) eines empfangenen HTTP-Pakets in ein Message-Objekt (org.apache.AXIS.Message) umgewandelt. Der ebenso vom Transport-Listener erzeugte MessageContext wird mit diesem Message-Objekt als Request-Nachricht und einer Reihe von Parameter initialisiert. Speziell bei HTTP wird z.B. die Eigenschaft http.SOAPAction gesetzt, da diese Information im HTTP-Header und nicht in der SOAP-Nachricht selbst enthalten ist. So können Informationen erhalten werden, die sich im Trägerprotokoll außerhalb der eigentlichen Nutzdaten befinden. Allerdings wird dies durch eine Aufweichung der Maxime der totalen Transportunabhängigkeit erkauft, da die protokollspezifischen Zusatzinformationen (http.SOAPAction) gesondert behandelt werden müssen.
Als weitere Eigenschaft wird der transportName auf "http" gesetzt. Anschließend wird der MessageContext vom Transport-Listener an die AXIS-Engine übergeben und dort folgendermaßen weiterverarbeitet:
MessageContext die Eigenschaft serviceHandler gesetzt worden sein, welche die zuständige Serviceklasse spezifiziert. Üblicherweise erledigt dies die Handler-Klasse URLMapper bereits im Transport-Bereich, wo die Request-URL des empfangenen HTTP-Pakets der entsprechenden Serviceklasse zugeordnet wird.
Der Chain im Service-Bereich (im Normalfall eine Instanz der Klasse SOAPService) enthält außer dem Request- und Response-Chain noch einen sogenannten Provider. Der Provider ist ein Handler, der als Brücke zwischen AXIS und der eigentlichen Zielanwendung (Target Service) fungiert.
Der Nachrichtenweg auf dem Client verläuft ähnlich der Serverseite, jedoch sind die drei Bereiche der AXIS-Engine in umgekehrter Reihenfolge durchlaufen. Der MessageContext wird hier von der Client-Applikation erzeugt und der AXIS-Engine übergeben. Im Transport-Bereich agiert ein spezieller Handler namens Sender, der alle protokollspezifischen Aufgaben erledigt um eine Nachricht zum SOAP-Server auf den Weg zu bringen bzw. wieder zu erhalten.
An einem Punkt des Nachrichtenwegs sendet ein Handler einen Request an die eigentliche Zielanwendung und empfängt daraufhin einen Response (bzw. verarbeitet einen Request und produziert einen Response). Innerhalb dieses Handler wird also von der Verarbeitung der eingehenden SOAP-Nachricht (Request) auf die Verarbeitung der ausgehenden SOAP-Nachricht (Response) umgeschaltet. Diese Art von Handler ist der sogenannte Pivot-Punkt. Die folgende Abbildung zeigt den Nachrichtenweg auf Client- und Serverseite. In den Abbildungen zum Nachrichtenweg auf dem Server(ServerMessagePath) bzw. Client (ClientMessagePath) wird der Pivot-Punkt in Form der Handler Provider und Sender implementiert.
Herkömmliche Chains speichern die enthaltenen Handler in einer
Vector-Klasse deren Elemente dann sequentiell abgearbeitet werden. Ein Targeted Chain ist eine spezielle Form eines Chain, der drei zusätzliche Felder für je einen Pivot-, Request- und Response-Handler besitzt. Im Gegensatz zu normalen Chains werden diese jeweils nur aufgerufen, wenn sich die Nachricht im Prozessfluss an der entsprechenden Stelle befindet. Trifft also ein MessageContext im Prozessfluss noch vor dem Erreichen des pivot-Punkts auf einen Targeted Chain, so werden außer den darin enthaltenen allgemeingültigen Handler auch noch diejenigen aus dem Request-Feld durchlaufen.
Beispielsweise stellt der SOAPService-Chain aus der Abbildung ServerMessagePath eine Form des Targeted Chain dar, bei dem alle drei zusätzlichen Felder mit Handler gefüllt wurden. Anzumerken ist, dass jeder der drei Handler auf Grund der Vererbungshierarchie (Abbildung chainclasses) einen Chain aufnehmen kann und somit nicht auf einen einzigen Handler beschränkt ist.
Das folgende Klassendiagramm zeigt wie Targeted Chains zu normalen Chains in Beziehung stehen.
AXIS umfasst mehrere zusammenarbeitende Subsysteme. Damit wird dem Ziel Rechnung getragen, AXIS modular zu halten und die jeweiligen Zuständigkeiten klar zu trennen. Diese Aufteilung ermöglicht eine gezielte Aktivierung bestimmter Teile des Systems. Die folgende Abbildung zeigt die Gliederung der Subsysteme. Subsysteme auf unteren Ebenen sind unabhängig von denen auf darüberliegenden Ebenen. Die hintereinander gestapelten Elemente können unabhängig voneinander genutzt werden, alternativ auch gemeinsam (z.B. HTTP und SMTP). Der Blick in den Quellcode verrät, dass die Subsysteme nicht so klar voneinander getrennt sind wie eigentlich beabsichtigt. Einige Subsysteme sind über verschiedene Java-Packages verteilt und manche Packages beinhalten Code von mehr als einem Subsystem. Beispielsweise befindet sich ein Servlet für die Administration der AXIS-Engine im gleichen Package wie Klassen, die für den Transportbereich zuständig sind. Die Trennung der Subsysteme im Quellcode wird frühestens nach Erscheinen der endgültigen Version 1.0 von AXIS erfolgen.
Grundsätzlich bedeutet Datenkodierung eine Transformation zwischen Werten eines Datentyps einer bestimmten Programmiersprache und dessen Repräsentation in XML. Um Daten als SOAP-Nachrichten verschicken zu können, müssen sie von ihrer ursprünglichen programmiersprachenspezifischen Form nach XML umgewandelt werden (Kodierung oder Serialisierung). Der Empfänger muss aus dem Inhalt der SOAP-Nachricht seinerseits wieder entsprechende Datenbehälter erzeugen und füllen (Dekodierung oder Deserialisierung). (De)Serialisierungs-Klassen für die einzelnen Datentypen erledigen die Kodierung. Die Zuordnung vom Java- bzw. XML-Datentyp zu der entsprechenden Klasse erfolgt an Hand einer Type Mapping Registry. Bei umfangreicheren Projekten wird man dennoch oft auf selbstprogrammierte (De)Serialisierungs-Klassen zurückgreifen müssen. In der Dokumentation zu AXIS wird diese Möglichkeit zwar erwähnt, gleichzeitig wird aber durch einen Kommentar darauf hingewiesen, dass eine ausführliche Beschreibung hierzu noch zu erstellen sei.
Für die Konfiguration einer AXIS-Engine werden Factory-Klassen und globale Einstellungen genutzt. Außerdem ist es möglich über statische WSDD-Dateien Einfluss zu nehmen. WSDD (Web Service Deployment Descriptor) basiert auf XML und dient der Installation und Konfiguration (
<deployment>) bzw. der Deinstallation (<undeployment>) von WebServices. Beispielsweise können hier Handler definiert und deren Ablaufreihenfolge in Chains festgelegt werden. Mit Hilfe des AXIS-Tools AdminClient können WSDD-Dateien an AXIS übergeben werden.
AXIS verfügt über ein primitives Administrations-Servlet, das es erlaubt, den AXIS-Server während des Betriebs zu stoppen bzw. wieder zu starten. Das Servlet bedient sich dabei eines speziellen WebServices, der in seiner Standardkonfiguration administrative Tätigkeiten nur vom lokalen Rechner aus zulässt. Eine Administration auch von außerhalb kann über einen Eintrag in der Konfigurationsdatei des AXIS-Servers (server-config.wsdd) aktiviert werden.
<service name="AdminService" provider="java:MSG">
<parameter name="className" value="org.apache.axis.util.Admin"/>
<parameter name="allowedMethods" value="*"/>
<parameter name="enableRemoteAdmin" value="true"/>
</service>
Davon ist jedoch dringend abzuraten, da standardmäßig keinerlei Authentifizierung für eine Administration notwendig ist.
Der Betrieb als unabhängiger autonomer Server ist zwar vorgesehen, muss aber auf Grund fehlender Optimierungen für den proffesionellen Einsatz eher als Notlösung betrachtet werden. Im Normalfall wird AXIS in eine vorhandene Serverumgebung eingebettet. Voraussetzung dafür ist die J2EE-Kompatibilität, wie sie z.B. IBM Websphere, BEA WebLogic, Apache Tomcat, Caucho Resin oder JBoss bieten. Dank der Servlet 2.2 Spezifikation erfolgt die Installation von AXIS als Webapplikation durch einen einfachen Kopiervorgang. Wie sich AXIS im praktischen Einsatz verhält soll nun das nächste Kapitel klären.
Ein Trend zur Vereinfachung ist in den letzten Jahren unübersehbar geworden. Im Java-Bereich ließ sich dies mit der Einführung von JSP (Java Server Pages) beobachten. Diese Technologie erlaubt eine relative einfache Erstellung von dynamischen Webinhalten, indem herkömmliche HTML-Tags und Java-Code in einer Datei kombiniert werden. Zur Laufzeit wird aus der JSP-Datei automatisch der Quellcode zu einem Servlet generiert und kompiliert. Die Schwelle für den massentauglichen Einstieg soll dadurch also so niedrig wie möglich gehalten werden. Was jedoch keineswegs bedeutet, JSP wäre nicht leistungsfähig. Gerade in Kombination mit anderen Java-Technologien wie Servlets, JavaBeans und TagLibs wird ein mächtiges Werkzeug für die Erstellung dynamischer Webseiten angeboten. Ähnliches lässt sich bei WebService-Frameworks erkennen. Beispielsweise bieten BEA mit Weblogic 7 und Microsoft mit .NET einfache Vorgehensweisen für das Erstellen von WebServices an. AXIS erlaubt es ebenso, WebServices mit einfachsten Mitteln anbieten zu können. Im Folgenden werden verschienene Implementierungsmöglichkeiten für WebServices und Clients anhand von Beispielen erläutert. AXIS wurde hierzu innerhalb des Servlet Containers Apache Tomcat als Webapplikation installiert und kann über die URL
http://localhost:8080/axis angesprochen werden.
Bei AXIS kann durch simples Umbenennen des Datei-Suffixes von
.java nach .jws (Java WebService) eine Java-Klasse als WebService eingesetzt werden. Es genügt, anschließend die jws-Datei in das AXIS-Verzeichnis des Servlet-Containers zu kopieren. Alle als public markierten Funktionen sind damit innerhalb des WebService veröffentlicht.
SimpleCalculator, die Methoden für die Rechenoperationen Addition und Subtraktion enthält:
public class SimpleCalculator {
public int add(int i1, int i2)
{
return i1 + i2;
}
public int subtract(int i1, int i2)
{
return i1 - i2;
}
}
Bemerkenswert ist, dass die verwendeten Klassen keinen AXIS-spezifischen Code enthalten müssen um sie als WebService zu publizieren. Nachdem die in SimpleCalculator.jws umbenannte Datei ins AXIS-Verzeichnis von Tomcat (%TOMCAT_HOME%/webapps/axis) kopiert wurde, kann der WebService von einem Client über folgende URL angesprochen werden:
http://localhost:8080/axis/SimpleCalculator.jwsEine Konfigurationsdatei (web.xml) des Servlet-Containers (Tomcat) sorgt dafür, dass alle Anfragen innerhalb der AXIS-Webapplikation mit dem Datei-Suffix "
.jws" vom AxisServlet entgegengenommen werden. Beim anschließenden Durchlaufen der AXIS-Engine überprüft der im globalen Chain eingehängte JWSHandler, ob der Name des WebService auf die Zeichenfolge ".jws" endet. In diesem Fall kompiliert der JWSHandler wenn nötig die entsprechende JWS-Datei und initialisiert sie als Ziel des entfernten Methodenaufrufs.
?WSDL" an die Adresse des WebService angehängt und beispielsweise mit Hilfe eines Browsers angefordert. AXIS generiert daraufhin vollautomatisch das WSDL-Dokument oder zeigt eine Fehlermeldung an:
http://localhost:8080/axis/SimpleCalculator.jws?WSDLObgleich JWS eine sehr einfache und schnelle Art und Weise darstellt WebServices zu publizieren, wird das Leistungspotential von AXIS hier nicht voll ausgeschöpft. Das Fehlen einer Konfigurationsmöglichkeit zieht folgende Einschränkungen nach sich:
public-Methoden kann zur ungewollten Publizierung von Funktionalitäten führen, was wiederum Sicherheitsprobleme hervorrufen kann.
Das auf XML basierende Format WSDD (Web Service Deployment Descriptor) bietet im Gegensatz zum Deployment per JWS weitgehende Freiheit bei der Erstellung und Konfiguration von WebServices. Eine WSDD-Datei legt dabei alle Modalitäten fest, wie AXIS die Funktionen einer Klasse als WebService veröffentlichen soll. Diese "Konfiguration von außen" ermöglicht eine Einbindung von Code, der in sich völlig unabhängig von AXIS ist. Zielsetzung ist es also bereits vorhandene Funktionalitäten in Form eines WebService zugänglich zu machen. Für die Einbindung dieser Funktionalitäten in AXIS müssen die Klassen in kompilierter Form vorliegen (
.class-Datei bzw. JAR-Archiv). Das hat den Vorteil, auch Klassen von Drittherstellern bei denen kein Quellcode zur Verfügung steht, als WebService publizieren zu können.
com.pixel.calculator und wurden in ein JAR-Archiv namens pixelCalc.jar gepackt. Die Klasse Calculator wurde um die Funktionen kart2polar und polar2kart erweitert. Sie dienen der Konvertierung von Vektor-Koordinaten vom kartesischen ins polare System und umgekehrt. Für die Kapselung der Rückgabewerte findet der komplexe Datentyp Object-Array bzw. die selbsdefinierte JavaBean-Klasse PolarBean Verwendung.
Neben dem eigentlichen WebService soll zusätzlich ein Handler aktiviert werden, der jeden Zugriff auf den WebService in einer Datei mitprotokolliert. Die gesamte WSDD-Datei (deploy.wsdd) sieht dann folgendermaßen aus:
<deployment xmlns="http://xml.apache.org/axis/wsdd/"
xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
<!-- Definition und Konfiguration des Log-Handlers -->
<handler name="log" type="java:LogHandler">
<parameter name="filename" value="calculator.log"/>
</handler>
<!-- Deployen des WebService -->
<service name="pixelCalc" provider="java:RPC">
<requestFlow>
<handler type="log"/>
</requestFlow>
<parameter name="className"
value="com.pixel.calculator.Calculator"/>
<parameter name="allowedMethods"
value="add subtract polar2kart kart2polar"/>
<beanMapping qname="myNS:PolarBean"
xmlns:myNS="urn:pixelCalcService"
languageSpecificType="java:com.pixel.calculator.PolarBean"/>
</service>
</deployment>
<deployment>
<deployment> ist entweder eine Installation und Konfiguration eines WebService in eine laufende AXIS-Engine möglich oder aber die Konfiguration der kompletten AXIS-Engine selbst. Alternativ existiert auch ein <undeployment>-Element, das die Deinstallation eines WebService oder Handler veranlässt.
<service>
name vergibt einen Namen für den WebService, mit dem er von außen angesprochen werden kann: http://<host>:<port>/services/axis/<WebService-Name>
provider sind als Werte "java:RPC" und "java:MSG" zugelassen. Sie definieren ob die Nachrichten RPC- oder Dokument-orientiert übertragen wird. Das Hauptaugenmerk liegt bei AXIS in synchronen RPC-Aufrufen.
<parameter>
<parameter> innerhalb des <service>-Elements lassen sich verschiedene Optionen festlegen, die sich explizit auf die Klasse mit den zu publizierenden Methoden beziehen:
className
allowedMethods
*" für eine Veröffentlichung aller public-Methoden der Klasse. Davon ist jedoch aus Sicherheitsgründen dringend abzuraten, da bei Erweiterungen der WebService-Klasse neue public-Methoden unkontrolliert veröffentlicht werden.scope
Application: Eine einzige Instanz für alle Anfragen.Request: Für jede Anfrage wird eine neue Instanz erzeugt (unter Umständen Performanceprobleme bei einer hohen Zahl gleichzeitiger Anfragen).Session: Bei Nutzung des AXIS-spezifischen Session-Managements wird pro Client genau eine Instanz erzeugt, unabhängig von der Anzahl der Aufrufe.<beanMapping>
<BeanMapping>-Element notwendig. Für nicht unterstützte komplexe Datentypen müssen eigene Serialisierungsklassen geschrieben werden, deren Anmeldung über das Element <typeMapping> erfolgt.
<handler>
<handler>-Element für die Definition und Konfiguration (<parameter>) des LogHandler. Über den festgelgten Namen lässt sich der Handler referenzieren und in verschiedene Bereiche einer AXIS-Engine einbinden.
Im Beispiel geschieht dies im Element <requestFlow> innerhalb der Service-Definition. Folglich wird der Handler also genau dann aktiviert, wenn das MessageContext-Objekt eines Aufrufs im AXIS-Server den Service-Bereich des WebService pixelCalc erreicht. Mit anderen Worten, jedesmal bevor AXIS den Aufruf an die Klasse Calculator weiterleitet, kommt der LogHandler zum Einsatz. Um auch die Aufrufe aller anderen WebServices zu protokollieren, müsste der LogHandler im Global-Bereich eingehängt werden.
AdminClient wird die WSDD-Datei an den laufenden AXIS-Server übergeben und ermöglicht sowohl die Aktivierung (<deployment>) als auch die Deaktivierung (<undeployment>) eines WebService. Die Konfiguration eines bereits vorhandenen WebService gleichen Namens wird bei einer erneuten Aktivierung überschrieben bzw. aktualisiert.
pixelCalc.jar in das entsprechende Bibliotheken-Verzeichnis der Webapplikation kopiert (%TOMCAT_HOME%/webapps/axis/WEB-INF/lib). Ähnlich verfährt man mit der Handler-Klasse LogHandler.class, die in das Verzeichnis für .class-Dateien kopiert wird (%TOMCAT_HOME%/webapps/axis/WEB-INF/classes).
Tomcat erkennt die hinzugefügten Dateien im Normalfall automatisch und bindet sie für einen späteren Zugriff automatisch ein. Im Produktionsbetrieb wird diese Funktion aus Gründen der Performance jedoch häufig deaktiviert. Mit Hilfe des Tomcat-Managers muss dann die AXIS-Webapplikation manuell neu gestartet werden:
http://localhost:8080/manager/reload?path=/axis
AdminClient die WSDD-Datei als Parameter übergeben wird:
java org.apache.axis.client.AdminClient deploy.wsdd
http://localhost:8080/axis/services/pixelCalc[?WSDL]
Für die Benutzung des WebServices wird ein Client benötigt. AXIS stellt Klassen zur Verfügung um mit einem WebService auf dem Server zu kommunizieren. Die Anfrage des Clients erfolgt standardmäßig über SOAP mit HTTP als Trägerprotokoll. Die eigentliche SOAP-Anfrage wird dabei indirekt per Hand generiert. Da eine bestimmte Methode des WebService aufgerufen werden soll, handelt es sich bei der Anfrage um einen Remote Procedure Call (RPC). Folgender Quellcode für einen einfachen Client soll dies verdeutlichen:
import org.apache.axis.client.Call;
import org.apache.axis.client.Service;
import org.apache.axis.encoding.XMLType;
import javax.xml.rpc.ParameterMode;
public class CalculatorTesterCall
{
public static void main(String [] args) throws Exception {
String wsUrl = "http://localhost:8080/axis/SimpleCalculator.jws";
String method = "subtract"; // Methodenname in der Serviceklasse
Integer i1 = new Integer(5); // Erster Operand
Integer i2 = new Integer(3); // Zweiter Operand
Service service = new Service();
Call call = (Call) service.createCall();
call.setTargetEndpointAddress( new java.net.URL( wsUrl ) );
call.setOperationName( method );
call.addParameter( "op1", XMLType.XSD_INT, ParameterMode.IN );
call.addParameter( "op2", XMLType.XSD_INT, ParameterMode.IN );
call.setReturnType( XMLType.XSD_INT );
Integer ret = (Integer) call.invoke( new Object [] { i1, i2 } );
System.out.println( "5 - 3 = " + ret);
}
}
Die Klasse Service dient als Factory für eine Instanz der Klasse Call, die für den dynamischen Aufruf des WebService zuständig ist. Die Klasse Call stellt dazu zentrale Konfigurationsmöglichkeiten zur Verfügung. Im Quellcode des Clients werden die WebService-Adresse, der entfernte Methodenname, die Parametertypen sowie der Datentyp des Rückgabewerts über entsprechende Methoden festgelegt. Die WebService-Adresse (wsUrl) könnte in diesem Fall alternativ auch auf das Beispiel aus Abschnitt WSDD zeigen, da beide eine Methode namens subtract mit gleichen Parametern anbieten. Der eigentliche Aufruf und damit das Abschicken der zuvor konfigurierten SOAP-Message erfolgt mit:
call.invoke( new Object [] { i1, i2 } )
Im Beispiel bedeutet dies, dass die zuvor mit dem Objekt call assoziierte Methode (subtract) auf dem Server aufgerufen wird. Für die Gewährleistung einer größtmöglichen Flexibilität werden Methodenparameter grundsätzlich als Array vom Typ Object übergeben. Um die Operanden primitiven Datentyps (int) als Parameter übergeben zu können, müssen diese erst mit der zugehörigen Wrapperklasse zu Objekten (Integer) gewandelt werden. Das Rückgabe-Objekt wurde über die Methode setReturnType auf den entsprechenden Datentyp festgelegt. Das Ergebnis des entfernten Methodenaufrufs steht nun zur Weiterverarbeitung bzw. zur Ausgabe bereit.
Das Implementierungsmodell von JAX-RPC sieht für den Client sogenannte statische Stubs bzw. Proxy-Klassen vor. Diese Klassen werden automatisch aus einer beliebigen WSDL generiert. Der Code für die Generierung der eigentlichen SOAP-Nachricht, wie im vorangegangenem Abschnitt, wandert dabei komplett in die Proxy-Klassen. Der Programmierer kann nach Instanziierung einer solchen Klasse, das Objekt benutzen als würde es lokal vorliegen. Die Generierung der Proxy-Klassen erfolgt über die von AXIS mitgelieferte Klasse
WSDL2Java:
java org.apache.axis.wsdl.WSDL2Java
-p calculatorstub
http://localhost:8080/axis/services/pixelCalc?WSDL
Mit Hilfe der Option -p werden die zu generierenden Proxy-Klassen einem Package zugeordnet. Als zweiter und letzter Parameter wird das WSDL-Dokument des WebService in Form einer lokalen Datei übergeben oder wie hier, dynamisch an Hand einer URL vom Server angefordert.
Nach Aufruf von WSDL2Java stehen im Unterverzeichnis calculatorstub folgende Klassen für die Programmierung des Clients zur Verfügung:
CalculatorService.java
CalculatorServiceLocator implementiert wird.CalculatorServiceLocator.java
Calculator.java
java.rmi.Remote), das die angebotenen Methoden des WebService enthält.PixelCalcSoapBindingStub.java
PolarBean.java
public class CalculatorProxyClient {
public static void main(String [] args) throws Exception {
// Erzeugen des Service
calculatorstub.CalculatorService service =
new calculatorstub.CalculatorServiceLocator();
// Stub/Proxy holen
calculatorstub.Calculator calc = service.getpixelCalc();
// RPC-Aufrufe
System.out.println("subtract(26 - 3) => " + calc.subtract(26, 3));
double x = -2.0;
double y = 0.0;
calculatorstub.PolarBean polar = calc.kart2Polar( x, y );
System.out.println("kart2polar("+x+", "+y+")" +
" => r=" + polar.getR() +
", phi=" + polar.getPhi() );
double[] kart = calc.polar2Kart( polar.getR(), polar.getPhi() );
System.out.println("polar2kart("+polar.getR()+", "+
polar.getPhi()+")" +
" => x=" + kart[0] +
", y=" + kart[1] );
}
}
Hatte man bei der Programmierung des Clients aus Abschnitt DII noch indirekt mit der Produzierung der SOAP-Nachricht für die Anfrage beim WebService zu tun, so entfällt dies hier komplett. Die Fehleranfälligkeit wird dadurch deutlich reduziert, da auf die Generierung der SOAP-Nachricht keinerlei Einfluss mehr genommen werden kann. Die Verantwortung für die Produzierung korrekter SOAP-Nachrichten wird damit auf AXIS bzw. der SOAP-Implementation im allgemeinen übertragen. Daher ist es umso wichtiger für Interoperabilität unter den einzelnen SOAP-Implementationen zu sorgen.
Hitzige Diskussionen, ob sich nun SOAP oder REST (Representational State Transfer) als Kommunikationsgrundlage von WebServices besser eignet, erregen derzeit die Gemüter. Die Kritiker von SOAP stören sich an dessen hoher Komplexität und betrachten die Implementierung in die vorhandene Infrastruktur als zu aufwändig. Als Alternative wird REST vorgeschlagen, das im wesentlichen einen vereinfachten Zugriff auf Ressourcen bietet (z.B. über HTTP-GET). Da das heutige WWW bereits eine Ausprägung dieser Architektur darstellt, könnte die vorhandene Infrastruktur ohne große Anpassungen effizienter für WebServices genutzt werden.
method) und der zu übergebenden Parameter (in0, in1 usw.) aus der WSDL extrahiert und an die WebService-URL angehängt werden. Das Ergebnis wird, wie bei einem herkömmlichen Aufruf, in Form einer SOAP-Nachricht zurückgeliefert. Für die Evaluierung eignet sich ein Web-Browser als Client, in dem folgende URL aufgerufen wird:
http://localhost:8080/axis/services/pixelCalc?method=add&in0=7&in1=9Versuche, einen WebService per HTTP-POST mit Hilfe eines HTML-Formulars aufzurufen, wurden von AXIS mit der SOAP-Fehlermeldung "
no SOAPAction header!" quittiert. Der SOAPAction Eintrag befindet sich im Header des HTTP-Protokolls, kann aber mit HTML nicht gesetzt werden.
Bei der Kommunikation per SOAP-over-HTTP wird ebenfalls HTTP-POST verwendet, wobei der SOAPAction Eintrag bei einer Anfrage jedoch obligatorisch ist. AXIS unterscheidet offensichtlich zwischen diesen beiden Fällen nicht und schließt bei Anfragen über HTTP-POST auf eine Kommunikation über SOAP-over-HTTP. Ist der SOAPAction Eintrag im HTTP-Header nicht vorhanden, geht AXIS daher von einer fehlerhaften Anfrage aus und liefert als Ergebnis eine SOAP-Nachricht mit einer entsprechenden Fehlermeldung zurück. Im Entwurf zur SOAP-Spezifikation Version 1.2 wird auf den SOAPAction Eintrag verzichtet, was einen Aufruf über ein Web-Formular per HTTP-POST in Zukunft erleichtern könnte.
Im Vergleich zum Vorgänger Apache SOAP wurde besonders durch die hohe Modularität eine wesentlich einfachere und flexiblere Erstellung von Webservices erreicht. Beim Redesign der Architektur stieg man aus Gründen der Performanz vom speicherhungrigen DOM-Modell auf das streamorientierte SAX-Modell um. Die Frage, warum AXIS beim Geschwindigkeitsvergleich mit Apache SOAP (und auch anderen WebService-Frameworks) trotzdem zurückliegt, bleiben die Entwickler schuldig. Ein möglicher Grund könnte darin liegen, dass die Entwicklung von AXIS noch lange nicht abgeschlossen ist. Viele Module befinden sich trotz der Veröffentlichung der "finalen" Version 1.0 noch immer in der Entwicklung. Auch die bisher vernachlässigte asynchrone Kommunikation taucht mittlerweile in den Quelldateien auf. Dieses Versäumnis lässt sich jedoch generell in der WebService-Welt beobachten. So existieren beispielsweise auch in WSDL 1.1 noch keine Bindings für den asynchronen Datenaustausch. Leider ist die Dokumentation zu AXIS immer noch als unzureichend anzusehen. Für das tiefere Verständnis einzelner Funktionalitäten -- sofern man von deren Existenz überhaupt weiß -- muss nicht selten der Quellcode zu Rate gezogen werden.
Allgemein wird Interoperabilität definiert durch die Fähigkeit von Hard- und Software, über die Grenzen verschiedener Computersysteme hinweg, miteinander kommunizieren zu können. Die Interoperabilität soll bei WebServices durch SOAP garantiert werden, das den Austausch von Daten und Funktionalitäten mit Hilfe standardisierter Nachrichten ermöglicht. Die jeweilige technologische Infrastruktur der Kommunikationspartner soll dabei frei wählbar sein. Dies hat nicht nur den Vorteil plattformübergreifend kommunizieren zu können, sondern verhindert auch eine generelle Festlegung auf eine Entwicklungsplattform. So ist es für die Entwicklung von WebServices auf Basis von XML, SOAP, WSDL und UDDI theoretisch problemlos möglich, beispielsweise von Microsofts .Net auf Java (oder umgekehrt) zu wechseln, ohne bestehende WebService-Partnerschaften zu gefährden. Bei garantierter Interoperabilität wird die Frage nach der zugrunde liegenden Plattform des WebService also völlig irrelevant. SOAP gilt als anerkanntes Basisprotokoll im Bereich der WebServices und somit als Grundpfeiler der Interoperabilität. In der Praxis treten jedoch noch einige Probleme zu Tage, nicht zuletzt hervorgerufen durch die hohe Flexibilität der SOAP 1.1 Spezifikation:
xsi:nil realisiert werden. Greift nun eine WebService-Umgebung auf die einzelnen Elemente der empfangenen Nachricht beispielsweise indiziert zu, so ergibt sich ein Problem, wenn der Kommunikationspartner Elemente mit leerem Inhalt legitimerweise weglässt anstatt sie mit einem xsi:nil-Attribut zu kennzeichnen.void bzw. ohne Rückgabeparameter gibt die SOAP Spezifikation keine eindeutige Auskunft. Als Rückgabewert könnte z.B. ein leeres SOAP-Envelope-Element, ein leeres SOAP-Element der Methodenrückgabe oder sogar der HTTP-Status 204 (No Response) generiert werden. Wenn der Aufrufer nicht die erwartete Fassung empfängt, kann dies zu Problemen führen.xsi:type-Attribute bei RPC-Parameter). Analoges lässt sich im Vorfeld mit Hilfe von WSDL erreichen. Schwierigkeiten können auftreten, falls WebService-Umgebungen auf dem einen oder anderen (oder auch beiden) Verfahren bestehen.SOAPAction im HTTP-Protokoll wird von der SOAP Spezifikation sehr vage als Intent (Zweckbestimmung) deklariert. Manche WebService-Umgebungen verzichten völlig auf die Auswertung des SOAPAction-Eintrags, andere hingegen verlangen ihn zwingend für die Zuordnung zum entsprechenden WebService.MustUnderstand einige Unklarheiten beseitigen soll.MustUnderstand einen Fehler ausgelöst hat.
Die IT-Industrie begann vor nun mehr als zwei Jahren über WebServices zu diskutieren. Die Vorzüge der Sprachen-Neutralität, Plattformunabhängigkeit und losen Verknüpfung wurden seitdem in verschiedenen Implementierungen und Pilotprojekten mehr und mehr sichtbar. Um WebServices für die Umsetzung von Geschäftsprozessen nicht nur firmenintern nutzen zu können, muss die Sicherheit als ein entscheidender Aspekt betrachtet werden. Im Jahre 2001 war der Bereich der Sicherheit noch deutlich unterrepräsentiert. Dies lag vor allem daran, dass 2001 die grundlegenden Standards auf Verbindungsebene entwickelt wurden (WSDL,SOAP,UDDI, usw.). Erst nachdem die Basis für die Kommunikation von WebServices geschaffen wurde, rückten weiterführende Themen wie Sicherheit ins Licht der Öffentlichkeit. Bei der Entwicklung wurde es jedoch versäumt die Kräfte zu vereinen und viele Hersteller versuchen nun eigene Protokolle zu entwickeln und zu etablieren -- insgesamt über 30. Meldungen und Ankündigungen von neuen "Standards" sind dementsprechend häufig.
Bei Geschäften im Internet muss auf den Datenaustausch vertraut werden. Die Gefahr des Diebstahls, des Verlusts oder der Manipulation der übertragenen Nachrichten ist dabei stets gegeben. Je nach Art des Geschäftsprozesses müssen verschiedene Anforderungen bezüglich Sicherheit erfüllt werden:
SSL Version 2 wird seit seiner Einführung im Jahr 1995 durch die Firma Netscape häufig zur Sicherung der Übertragung zwischen Browser und Webserver eingesetzt. SSL arbeitet auf der Session-Ebene des ISO-OSI-Schichtenmodells und verschlüsselt Pakete der Applikations-Ebene. HTTP-Pakete können so mit Hilfe von SSL verschlüsselt übertragen werden (HTTP-over-SSL bzw. HTTPS). SSL ermöglicht die Erfüllung der im Abschnitt securityDefinition gestellten Anforderungen in den Punkten Vertraulichkeit, Integrität und Authentifizierung. Die Authentifizierung erfolgt durch Überprüfung eines Zertifikats, das die Identität garantieren soll. Dieses Verfahren kann sowohl auf den Server als auch auf den Client angewendet werden. Zertifikate können zum einen von einer CA (Certification Authority) ausgestellt werden, zum anderen existiert aber auch die Möglichkeit sich das Zertifikat einfach selbst auszustellen.
Im B2C-Bereich erfolgt bei SSL üblicherweise nur eine serverseitige Authentifizierung, da dem Kunden ein Erwerb eines Zertifikats nicht zugemutet werden soll. In diesem Fall muss die Identifizierung des Kunden auf anderem Wege erfolgen (Username und Passwort über HTML-Formular, HTTP Basic Authentication). Mögliche Missbräuche werden zugunsten der Bequemlichkeit in Kauf genommen. Wird der Client beispielsweise beim Anmeldeverfahren an einen anderen Server umgeleitet, so kann dieser unter Vorgaukelung der gleichen graphischen Oberfläche leicht an die Login-Daten des Benutzers kommen. Ermöglicht wird dies dadurch, dass der Client das Zertifikat des Servers zwar auf Gültigkeit überprüft, jeder Server sich jedoch sein eigenes gültiges Zertifikat ausstellen kann. Nur die gegenseitige Authentifizierung über Zertifikate würde für mehr Sicherheit sorgen, da hier eine Anmeldung über das Zertifikat des Benutzers erfolgen kann und somit das Ausspionieren der Login-Daten gar nicht erst möglich wird. Für den Einsatz im Bereich von WebServices ergeben sich zusätzliche Aspekte.
In komplexeren WebServices-Topologien kann es nötig sein, sogenannte Intermediaries einzusetzen. Intermediaries stellen eine Art Router für SOAP-Nachrichten dar und erfüllen Aufgaben wie Load-Balancing, Skalierbarkeit, Proxy, Trust-Domain und so weiter. SOAP-Nachrichten besitzen einen Header, in dem Informationen für Intermediaries enthalten sein können. Läuft die Kommunikation zwischen Client und WebService über SSL, kann dies zu Problemen führen, wenn ein Intermediary als Vermittler fungiert und Auswertungen bzw. Veränderungen an der übertragenen SOAP-Nachricht vornehmen soll. Bei reiner Routing-Funktion des Intermediary für die verschlüsselten Pakete wäre ein Zugriff auf die SOAP-Nachrichten nicht möglich. Er muss also selbst als SSL-Server auftreten und die vom Client empfangenen Pakete dekodieren. Nach Auswertung der SOAP-Nachricht wird sie vom Intermediary (nun in der Funktion eines SSL-Clients) erneut verschlüsselt und zum Webservice (SSL-Server) übertragen. Wie in Abbildung point2point zu sehen ist, herrscht nur zwischen den einzelnen Stationen ein sogenannter Sicherheitskontext, in dem die Vertraulichkeit gewahrt wird. Somit haben nicht nur Client und WebService Zurgriff auf den Inhalt der übermittelten Nachricht sondern auch der Intermediary selbst. Weder Vertraulichkeit, Integrität noch Authentifizierung kann bei einer Punkt-zu-Punkt Konfiguration mit reiner SSL-Verschlüsselung garantiert werden. Gefahr droht zum einen bei Kompromittierung des Intermediary, der in dieser Konfiguration für Datenschnüffler eine enorme Attraktivität ausstrahlen dürfte. Auch von der Nutzung eines externen Intermediary von Drittanbietern muss in diesem Falle abgeraten werden. Außerdem ist bei der Punkt-zu-Punkt Konfiguration eine SSL-Authentifizierung von Client bzw. WebService nicht mehr möglich, da dem Intermediary für die Verschlüsselung der weiterzuleitenden Nachrichten das Zertifikat des ursprünglichen Senders nicht zur Verfügung steht.
Für WebServices der ersten Generation, was dem momentanen Stand der Dinge entspricht, kann SSL durchaus als einfacher Schutz vor dem Mitlesen übertragener Pakete dienen. Sobald auch Intermediaries eingesetzt werden sollen, reicht eine Punkt-zu-Punkt Verschlüsselung ganzer Datenpakete jedoch nicht aus. WebServices der zweiten Generation, die mit Hilfe von Intermediaries erweiterte Funktionalitäten bieten sollen, muss daher eine End-zu-End Verschlüsselung zum Einsatz kommen. Die Verschlüsselung und die Entschlüsselung findet bei einer End-zu-End Übertragung nur bei dem eigentlichen Sender (Client) bzw. Empfänger (WebService) statt. Die Pakete des Trägerprotokolls bzw. die enthaltene SOAP-Nachrichten werden bei dieser Konfiguration jedoch nicht als Ganzes verschlüsselt. Kodiert wird nur der SOAP-Body einer Nachricht, der die zu schützenden Daten enthält. Somit wird den Intermediaries weiterhin ein Zugriff auf den SOAP-Header für die Erfüllung ihrer Aufgaben gewährt, ohne dass sie Zugriff auf die sensitiven Nutzdaten im SOAP-Body hätten. Auch eine Kombination der beiden Modi ist denkbar. So könnte bei einer End-zu-End Konfiguration (mit unverschlüsseltem SOAP-Header und Trägerprotokoll) zusätzlich eine SSL-Verschlüsselung des Trägerprotokolls zwischen den einzelnen Stationen erfolgen.
SAML (Security Assertion Markup Language) ist ein auf XML basierendes Framework für den Austausch von Authentifizierungs- und Autorisierungsdaten in verteilten Anwendungen. Dabei sollen existierende Standard-Protokolle und Messaging Frameworks sowie Standards wie XML Digital Signatures und XML Encryption genutzt werden. Im Dezember 2000 wurde auf Initiative der Firma Netegrity bei OASIS ein Komitee namens Security Services eingerichtet, das sich um die Entwicklung von SAML kümmert. Mit einer endgültigen Verabschiedung des SAML-Standards wird im Herbst 2002 gerechnet.
firmaX.de.firmaX.de einen Link zu der Ziel-Webseite reisenY.de an, bei der er einen Flug buchen möchte. Der Link könnte dann so aussehen:
https://firmaX.de?ziel=reisenY.de/flugbuchung.jsp
firmaX.de liefert dem Benutzer eine Authentifizierungs-Referenz (name assertion reference). Anschließend wird der Benutzer zur Ziel-Webseite reisenY.de weitergeleitet.https://reisenY.de?ziel=reisenY.de/flugbuchung.jsp&SAMLAuth=<authref>
reisenY.de fordert nun ein Authentifizierungs-Dokument (name assertion) von der Basis-Webseite firmaX.de an und schickt dabei die eben erhaltene Authentifizierungs-Referenz des Benutzers mit.firmaX.de liefert das Authentifizierungs-Dokument zurück, woraufhin die Ziel-Webseite reisenY.de an Hand der enthaltenen Attribute über eine Autorisation des Benutzers entscheidet.
Das Fehlen weiterführender Sicherheitsstandards kristallisiert sich immer mehr zum Flaschenhals für den Einsatz von WebServices im elektronischen Handel heraus. Im April 2002 veröffentlichten IBM, Microsoft und VeriSign gemeinsam eine Spezifikation namens WS-Security, welche selbst wieder ein Konglomerat verschiedener Spezifikationen enthält. Dies ist bereits die zweite Zusammenarbeit von IBM und Microsoft zu dem Zwecke, ihren Vorschlägen mehr Nachdruck zu verleihen. Zwei Monate später wurde WS-Security OASIS (Organization for the Advancement of Structured Information Standards) zur weiteren Entwicklung übergeben. Zur gleichen Zeit bekannte sich auch überraschend Sun Microsystems zu WS-Security, obwohl das Unternehmen bereits eigene Spezifikationen zum Thema Sicherheit entwickelt hatte. Damit eröffnen sich WS-Security gute Chancen zum allgemein akzeptierten Standard zu reifen. Die WS-Security Spezifikation beschreibt für die Sicherung von WebServices eine Erweiterung von SOAP-Nachrichten. Beschrieben wird, wie Integrität, Vertraulichkeit und Authentifikation für Nachrichten in einer plattformunabhängigen Art und Weise erreicht werden kann. Diese Mechanismen dienen als Grundlage für weiterführender Sicherheitsmodelle und Verschlüsselungstechnologien, wie in folgender Roadmap dargestellt wird.
<Sicherheit>-Elements im SOAP-Header. Folgende Informationsarten können im <Sicherheit>-Element enthalten sein:
Das größte Problem beim Thema Sicherheit stellt momentan der Faktor Zeit dar. Zwar ergänzen sich SAML und WS-Security in vielen Punkten und besitzen gute Chancen den kommenden Sicherheitsstandard zu bilden, jedoch ist mit der Fertigstellung aller beteiligten Spezifikationen und ihrer praxistauglichen Implementierung frühestens in einem Jahr zu rechnen. Da aber viele potentielle Anbieter von kommerziellen Webservices auf die Bereiche Sicherheit und Transaktionalität angewiesen sind, könnte die Überbrückung der zeitlichen Kluft bis zum Vorhandensein von Standards einen entscheidenden Aspekt für den Durchbruch von WebServices darstellen. Zum einen kann versucht werden auf bereits vorhandene Implementationen (z.B. OpenSAML) zurückzugreifen um eine eigene rudimentäre Sicherheitslösung aufzubauen. Eine andere Möglichkeit besteht in der Nutzung von pragmatischen Sicherheitslösungen. Zur Erreichung der angestrebten Ziele finden hier vorhandene und zukünftige Spezifikationen natürlich nur sekundär Berücksichtigung. Beispielsweise bietet die Firma Vordel seit geraumer Zeit ein umfassendes Paket für Sicherheit und Transaktionalität an, das in Form eines "Gatekeepers" vor den eigentlichen WebServices gesetzt wird. Kurzfristig können auf diese Weise die Voraussetzungen für das Anbieten von gesicherten WebServices geschaffen werden. Langfristig sollte jedoch auch aus Gründen der Interoperabilität, die etwa für Single Sign-On eine entscheidende Rolle spielt, auf offenen Standards beruhende Lösungen zurückgegriffen werden.
Das Konzept plattformunabhängiger loser Dienste, die sich flexibel miteinander koppeln lassen erscheint durchaus interessant. Kombiniert mit der Möglichkeit über ein globales Verzeichnis jederzeit auf den günstigsten Anbieter zugreifen zu können, überzeugen WebServices auch aus ökonomischer Sicht. Ungeachtet der Tatsache, dass bereits ähnliche Technologien existieren (COM, CORBA, RMI), begann im Jahr 2001 die Industrie unter großem Marketingaufwand den Siegeszug von WebServices in den Köpfen der Entwickler und Entscheider vorzubereiten.
Alle Beispiele zum Download: da_webservices_quellcode.zip
public class SimpleCalculator {
public int add(int i1, int i2)
{
return i1 + i2;
}
public int subtract(int i1, int i2)
{
return i1 - i2;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions
targetNamespace="http://localhost:8080/axis/SimpleCalculator.jws"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:apachesoap="http://xml.apache.org/xml-soap"
xmlns:impl="http://localhost:8080/axis/SimpleCalculator.jws"
xmlns:intf="http://localhost:8080/axis/SimpleCalculator.jws"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<wsdl:types/>
<wsdl:message name="addRequest">
<wsdl:part name="i1" type="xsd:int"/>
<wsdl:part name="i2" type="xsd:int"/>
</wsdl:message>
<wsdl:message name="addResponse">
<wsdl:part name="addReturn" type="xsd:int"/>
</wsdl:message>
<wsdl:message name="subtractRequest">
<wsdl:part name="i1" type="xsd:int"/>
<wsdl:part name="i2" type="xsd:int"/>
</wsdl:message>
<wsdl:message name="subtractResponse">
<wsdl:part name="subtractReturn" type="xsd:int"/>
</wsdl:message>
<wsdl:portType name="SimpleCalculator">
<wsdl:operation name="add" parameterOrder="i1 i2">
<wsdl:input message="intf:addRequest" name="addRequest"/>
<wsdl:output message="intf:addResponse" name="addResponse"/>
</wsdl:operation>
<wsdl:operation name="subtract" parameterOrder="i1 i2">
<wsdl:input message="intf:subtractRequest" name="subtractRequest"/>
<wsdl:output message="intf:subtractResponse" name="subtractResponse"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="SimpleCalculatorSoapBinding" type="intf:SimpleCalculator">
<wsdlsoap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="add">
<wsdlsoap:operation soapAction=""/>
<wsdl:input name="addRequest">
<wsdlsoap:body use="encoded"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="http://localhost:8080/axis/SimpleCalculator.jws"/>
</wsdl:input>
<wsdl:output name="addResponse">
<wsdlsoap:body use="encoded"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="http://localhost:8080/axis/SimpleCalculator.jws"/>
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="subtract">
<wsdlsoap:operation soapAction=""/>
<wsdl:input name="subtractRequest">
<wsdlsoap:body use="encoded"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="http://localhost:8080/axis/SimpleCalculator.jws"/>
</wsdl:input>
<wsdl:output name="subtractResponse">
<wsdlsoap:body use="encoded"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="http://localhost:8080/axis/SimpleCalculator.jws"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="SimpleCalculatorService">
<wsdl:port name="SimpleCalculator" binding="intf:SimpleCalculatorSoapBinding">
<wsdlsoap:address location="http://localhost:8080/axis/SimpleCalculator.jws"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
package com.pixel.calculator;
public class Calculator {
public int add(int i1, int i2)
{
return i1 + i2;
}
public int subtract(int i1, int i2)
{
return i1 - i2;
}
public double[] polar2kart(double r, double phi)
{
double x = Math.abs(r) * Math.cos(phi);
double y = Math.abs(r) * Math.sin(phi);
double[] kart = { x, y };
return kart;
}
public PolarBean kart2polar(double x, double y)
{
double r = Math.sqrt( x*x + y*y );
double phi = Math.atan2( y, x );
PolarBean polarBean = new PolarBean();
polarBean.setR( r );
polarBean.setPhi( phi );
return polarBean;
}
}
package com.pixel.calculator;
public class PolarBean {
private double r = 0.0;
private double phi = 0.0;
public void setR(double value)
{ r = value; }
public double getR()
{ return r; }
public void setPhi(double value)
{ phi = value; }
public double getPhi()
{ return phi; }
}
import org.apache.axis.AxisFault;
import org.apache.axis.Handler;
import org.apache.axis.MessageContext;
import org.apache.axis.handlers.BasicHandler;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.util.Date;
public class LogHandler extends BasicHandler {
public void invoke(MessageContext msgContext) throws AxisFault
{
/** Log an access each time we get invoked.
*/
try {
Handler serviceHandler = msgContext.getService();
String filename = (String)getOption("filename");
if ((filename == null) || (filename.equals("")))
throw new AxisFault("Server.NoLogFile",
"No log file configured for the LogHandler!",
null, null);
FileOutputStream fos = new FileOutputStream(filename, true);
PrintWriter writer = new PrintWriter(fos);
Integer numAccesses =
(Integer)serviceHandler.getOption("accesses");
if (numAccesses == null)
numAccesses = new Integer(0);
numAccesses = new Integer(numAccesses.intValue() + 1);
Date date = new Date();
String result = date + ": service " +
msgContext.getTargetService() +
" accessed " + numAccesses + " time(s).";
serviceHandler.setOption("accesses", numAccesses);
writer.println(result);
writer.close();
} catch (Exception e) {
throw AxisFault.makeFault(e);
}
}
}
<!-- Use this file to deploy some handlers/chains and services -->
<!-- Two ways to do this: -->
<!-- java org.apache.axis.client.AdminClient deploy.wsdd -->
<!-- after the axis server is running -->
<!-- or -->
<!-- java org.apache.axis.utils.Admin client|server deploy.wsdd -->
<!-- from the same directory that the Axis engine runs -->
<deployment xmlns="http://xml.apache.org/axis/wsdd/"
xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
<!-- Definition und Konfiguration des Log-Handlers -->
<handler name="log" type="java:LogHandler">
<parameter name="filename" value="calculator.log"/>
</handler>
<!-- Deployen des WebService -->
<service name="pixelCalc" provider="java:RPC">
<requestFlow>
<handler type="log"/>
</requestFlow>
<parameter name="className"
value="com.pixel.calculator.Calculator"/>
<parameter name="allowedMethods"
value="add subtract polar2kart kart2polar"/>
<beanMapping qname="myNS:PolarBean"
xmlns:myNS="urn:pixelCalcService"
languageSpecificType="java:com.pixel.calculator.PolarBean"/>
</service>
</deployment>
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions
targetNamespace="http://localhost:8080/axis/services/pixelCalc"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:apachesoap="http://xml.apache.org/xml-soap"
xmlns:impl="http://localhost:8080/axis/services/pixelCalc"
xmlns:intf="http://localhost:8080/axis/services/pixelCalc"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:tns1="urn:pixelCalcService"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<wsdl:types>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://localhost:8080/axis/services/pixelCalc">
<import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>
<complexType name="ArrayOf_xsd_double">
<complexContent>
<restriction base="soapenc:Array">
<attribute ref="soapenc:arrayType"
wsdl:arrayType="xsd:double[]"/>
</restriction>
</complexContent>
</complexType>
<element name="ArrayOf_xsd_double" nillable="true"
type="impl:ArrayOf_xsd_double"/>
</schema>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="urn:pixelCalcService">
<import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>
<complexType name="PolarBean">
<sequence>
<element name="phi" type="xsd:double"/>
<element name="r" type="xsd:double"/>
</sequence>
</complexType>
<element name="PolarBean" nillable="true" type="tns1:PolarBean"/>
</schema>
</wsdl:types>
<wsdl:message name="kart2polarRequest">
<wsdl:part name="in0" type="xsd:double"/>
<wsdl:part name="in1" type="xsd:double"/>
</wsdl:message>
<wsdl:message name="kart2polarResponse">
<wsdl:part name="kart2polarReturn" type="tns1:PolarBean"/>
</wsdl:message>
<wsdl:message name="polar2kartRequest">
<wsdl:part name="in0" type="xsd:double"/>
<wsdl:part name="in1" type="xsd:double"/>
</wsdl:message>
<wsdl:message name="polar2kartResponse">
<wsdl:part name="polar2kartReturn" type="intf:ArrayOf_xsd_double"/>
</wsdl:message>
<wsdl:message name="addRequest">
<wsdl:part name="in0" type="xsd:int"/>
<wsdl:part name="in1" type="xsd:int"/>
</wsdl:message>
<wsdl:message name="addResponse">
<wsdl:part name="addReturn" type="xsd:int"/>
</wsdl:message>
<wsdl:message name="subtractRequest">
<wsdl:part name="in0" type="xsd:int"/>
<wsdl:part name="in1" type="xsd:int"/>
</wsdl:message>
<wsdl:message name="subtractResponse">
<wsdl:part name="subtractReturn" type="xsd:int"/>
</wsdl:message>
<wsdl:portType name="Calculator">
<wsdl:operation name="kart2polar" parameterOrder="in0 in1">
<wsdl:input name="kart2polarRequest"
message="intf:kart2polarRequest"/>
<wsdl:output name="kart2polarResponse"
message="intf:kart2polarResponse"/>
</wsdl:operation>
<wsdl:operation name="polar2kart" parameterOrder="in0 in1">
<wsdl:input name="polar2kartRequest"
message="intf:polar2kartRequest"/>
<wsdl:output name="polar2kartResponse"
message="intf:polar2kartResponse"/>
</wsdl:operation>
<wsdl:operation name="add" parameterOrder="in0 in1">
<wsdl:input name="addRequest" message="intf:addRequest"/>
<wsdl:output name="addResponse" message="intf:addResponse"/>
</wsdl:operation>
<wsdl:operation name="subtract" parameterOrder="in0 in1">
<wsdl:input name="subtractRequest" message="intf:subtractRequest"/>
<wsdl:output name="subtractResponse" message="intf:subtractResponse"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="pixelCalcSoapBinding" type="intf:Calculator">
<wsdlsoap:binding style="rpc"
transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="kart2polar">
<wsdlsoap:operation soapAction=""/>
<wsdl:input name="kart2polarRequest">
<wsdlsoap:body use="encoded"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="http://localhost:8080/axis/services/pixelCalc"/>
</wsdl:input>
<wsdl:output name="kart2polarResponse">
<wsdlsoap:body use="encoded"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="http://localhost:8080/axis/services/pixelCalc"/>
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="polar2kart">
<wsdlsoap:operation soapAction=""/>
<wsdl:input name="polar2kartRequest">
<wsdlsoap:body use="encoded"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="http://localhost:8080/axis/services/pixelCalc"/>
</wsdl:input>
<wsdl:output name="polar2kartResponse">
<wsdlsoap:body use="encoded"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="http://localhost:8080/axis/services/pixelCalc"/>
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="add">
<wsdlsoap:operation soapAction=""/>
<wsdl:input name="addRequest">
<wsdlsoap:body use="encoded"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="http://localhost:8080/axis/services/pixelCalc"/>
</wsdl:input>
<wsdl:output name="addResponse">
<wsdlsoap:body use="encoded"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="http://localhost:8080/axis/services/pixelCalc"/>
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="subtract">
<wsdlsoap:operation soapAction=""/>
<wsdl:input name="subtractRequest">
<wsdlsoap:body use="encoded"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="http://localhost:8080/axis/services/pixelCalc"/>
</wsdl:input>
<wsdl:output name="subtractResponse">
<wsdlsoap:body use="encoded"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="http://localhost:8080/axis/services/pixelCalc"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="CalculatorService">
<wsdl:port binding="intf:pixelCalcSoapBinding" name="pixelCalc">
<wsdlsoap:address
location="http://localhost:8080/axis/services/pixelCalc"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>