Technologien Einleitung Dieses Dokument soll einen Einblick in die Technologien geben, die in den Tutorials angewendet werden. Natürlich werden alle Themen nur kurz angesprochen und für tieferes Hintergrundwissen wird das Durcharbeiten entsprechender Literatur empfohlen. @Autor Andre Haferkorn Inhaltsverzeichnis 1 XML__________________________________________________ 1 1.1 Aufbau von XML______________________________________________ 1.2 XML-Namespaces ____________________________________________ 1.3 XML Schema (XSD) ___________________________________________ 1.3.1 XSD Simple Type __________________________________________ 1.3.2 XSD Complex Type ________________________________________ 1.3.3 XML Schema und Namespaces _______________________________ 1.3.4 XML-Dokumente mit XML Schema_____________________________ 1.4 Verarbeitung von XML _________________________________________ 1.4.1 DOM ____________________________________________________ 1.4.2 SAX ____________________________________________________ 1.4.3 JAXP ____________________________________________________ 2 2.1 2.2 3 3.1 3.2 4 1 1 2 3 3 3 4 5 5 6 7 WSDL ________________________________________________ 9 Was ist WSDL ________________________________________________ 9 Aufbau von WSDL-Dokumenten _________________________________ 9 SOAP _______________________________________________ 11 Was ist SOAP _______________________________________________ 11 Aufbau von SOAP ___________________________________________ 11 AXIS ________________________________________________ 12 4.1 Was ist Axis ________________________________________________ 4.2 Web Services mit Axis ________________________________________ 4.2.1 Web Services erstellen als Java Web Service (jws) _______________ 4.2.2 Web Service erstellen mit WSDD _____________________________ 4.2.3 Web Service erstellen als Web Applikation______________________ 4.3 Axis und WSDL _____________________________________________ 4.3.1 Java2WSDL _____________________________________________ 4.3.2 WSDL2Java _____________________________________________ 12 12 12 13 14 15 15 15 1 XML Dieses Tutorial soll kein Handbuch für XML darstellen. Dafür gibt es genügend Bücher. An dieser Stelle werden nur die Grundlagen für die weiteren Beispiele gelegt. 1.1 Aufbau von XML XML steht für Extensible Markup Language und ist ein Standard zur Erstellung strukturierter Dokumente. ‚Strukturiert’ bedeutet, dass die Teile des Dokumentes, die Elemente, einer Baumstruktur folgen. Jeder Teil dieses Baumes, von der Wurzel (Root-Element) bis zu den Blättern (Text-Wert) stellt einen Knoten dar (node). Ein Knoten kann weitere Knoten, so genannte Kindknoten (child nodes), beinhalten. Der Elternknoten (parent node) gruppiert die Kindknoten durch Umschließen mit einem Start-Tag <element> und einem End-Tag </element>. Die Tags wirken dabei als eine Art Klammern. Das äußerste Klammernpaar ist die Wurzel. In einem wohlgeformten XML-Dokument darf es nur einen Wurzelknoten geben. Das folgende XML-Dokument verdeutlicht den Zusammenhang. In diesem Beispiel ist <Person> der Wurzelknoten und <Name>, <Adresse> und <Telefon> sind dessen Kindknoten. <?xml version="1.0" encoding="UTF-8"?> <Person> <Name>Max Mustermann</Name> <Adresse>Hauptstr. 1, 01234 Irgendwo</Adresse> <Telefon>+49/321/123456-100</Telefon> </Person> 1.2 XML-Namespaces Die oben verwendeten Elemente-Namen sind Weltweit nicht eindeutig. So gibt es sicher Firmen, die eine Person anders definieren würden. Um den Element-Namen eindeutig zu machen, wird er um einen (weltweit) eindeutigen Bezeichner, den Namespace (z. B. http://my-domain.com/Person), erweitert. Der Namespace ist hierbei nichts weiter als eine Zeichenkette. Üblicherweise wird der String in Form einer URL verwendet, denn durch diese ist die Eindeutigkeit gewährleistet – der Domain-Anteil ist immer nur einer bestimmten Organisation/Person zugeordnet. Außerdem wird oft an die Stelle, auf die der Link verweist die genaue Spezifikation der Dokumentenstruktur hinterlegt. Es kann nun passieren, dass in einem XML-Dokument gleiche Element-Namen von unterschiedlichen Organisationen verwendet werden. Deshalb empfiehlt es sich bei der Verwendung eines Elements immer den Namespace mit anzugeben. Im obigen Fall würden die Elemente-Namen dadurch recht lang werden. Deshalb gibt es Namespace-Präfixe. Diese müssen nur Dokumentweit eindeutig sein und können deshalb viel kürzer sein. Ein Dokument, dessen Elemente Namespace-Präfixe verwenden, kann z. B. so aussehen. <?xml version="1.0" encoding="UTF-8"?> <myns:Person xmlns:myns="http://my-domain.com/Person"> <myns:Name>Max Mustermann</myns:Name> <myns:Adresse>Hauptstr. 1, 01234 Irgendwo</myns:Adresse> <myns:Telefon>+49/321/123456-100</myns:Telefon> </myns:Person> 1 Gibt es nur einen Namespace im gesamten Dokument (bzw. für einen Elternknoten und seine Kindknoten) so kann ein Default-Namespace im Wurzel-Knoten (bzw. im jeweiligen Elternknoten) in der Form xmlns="Namespace-URI" festgelegt und auf die Angabe von Präfixen verzichtet werden. <?xml version="1.0" encoding="UTF-8"?> <Person xmlns="http://my-domain.com/Person"> <Name>Max Mustermann</Name> <Adresse>Hauptstr. 1, 01234 Irgendwo</Adresse> <Telefon>+49/321/123456-100</Telefon> </Person> 1.3 XML Schema (XSD) XSD steht für XML-Schema Definition (oder kurz XML Schema). Ein XML Schema ist ein XML-Dokument, das Meta-Informationen über den Aufbau einer XML-Datei beinhaltet. Eine XSD-Datei kann man sich also als eine Art Klasse vorstellen, in der Eigenschaften und deren Struktur definiert werden. Die mit dem XML Schema erstellten XML-Dokumente sind dann sozusagen Instanzen dieser Klasse, in denen den Eigenschaften konkrete Werte zugewiesen werden. Nur wenn die Eigenschaften, deren Werte und die Struktur des XML-Dokumentes den Vorgaben des XML Schemas entsprechen, spricht man von einem gültigen (valid) XMLDokument. Das im letzten Abschnitt gezeigte Beispiel könnte z. B. eine Instanz des folgenden XML Schemas sein. <?xml version="1.0" encoding="UTF-8"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:element name="Person"> <xsd:complexType> <xsd:sequence> <xsd:element name="Name" type="xsd:string"/> <xsd:element name="Adresse" type="xsd:string"/> <xsd:element name="Telefon" type="xsd:string"/> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:schema> Die Angabe des Namespace für das XML Schema zeigt, dass es sich bei dieser Datei um ein XML Schema handelt, denn eigentlich ist es ja auch nur ein (gewöhnliches) XML-Dokument. Die für das Schema verfügbaren Elemente und deren Struktur werden hier jedoch nicht durch ein (weiteres) XML Schema, sondern durch eine Spezifikation des W3C festgelegt. XMLEditoren sowie XML-Parsern müssen die Regeln dieser Spezifikation bekannt sein. In der XSD-Datei wurden als Typen für die Elemente, bis auf das Root-Element, nur der primitive XSD-Datentyp xsd:string verwendet. Gerade bei der Telefonnummer wäre eine gewisse Einschränkung der Zeichen wünschenswert. XML Schema bietet deshalb die Möglichkeit eigene Datentypen zu erstellen. Dabei wird zwischen ‚einfachen’ (simple) und ‚komplexen’ (complex) Datentypen unterschieden. 2 1.3.1 XSD Simple Type Eine Telefonnummer folgt immer einem bestimmten Format. Es wäre wünschenswert, wenn der Leser (das kann auch eine Maschine sein) in einem XML-Dokument auch nur Telefonnummern vorfindet, die diesem Format entsprechen. Ein solches Format kann zum Beispiel als xsd:simpleType definiert sein. <xsd:simpleType name="TelefonType"> <xsd:restriction base="xsd:token"> <xsd:pattern value="((([0]{2}|[+])[0-9]{2}([/]|[ ]))|[0])([1-9]{2,5}([/]|[ ])[0-9]{3,}([-][0-9]+)?)"/> </xsd:restriction> </xsd:simpleType> Mit dem Element xsd:pattern wird das Format der Telfonnummer festgelegt. Der Wert eines Elementes, das diesen Datentyp verwendet, kann z. B. folgender sein: 0321 123456. 1.3.2 XSD Complex Type xsd:comlexType entspricht einer Datenstruktur (in Programmiersprachen unter dem Begriff struct bekannt). Ein Element mit einem komplexen Datentyp kann Kindelemente primitiver, einfacher oder komplexer Datentypen enthalten. Der komplexe Datentyp für eine Person wurde ja bereits in einem Beispiel gezeigt. Auch für den komplexen Datentyp kann das Attribut name gesetzt werden, um diesen Datentyp mehrfach im XML Schema zu verwenden. <xsd:complexType name="PersonType"> <xsd:sequence> <xsd:element name="Name" type="xsd:string"/> <xsd:element name="Adresse" type="xsd:string"/> <xsd:element name="Telefon" type="TelefonType"/> </xsd:sequence> </xsd:complexType> 1.3.3 XML Schema und Namespaces Im Kapitel 1.2 wurde bereits der Begriff Namespace erklärt. So können mehrdeutige Elemente-Namen wie Person durch Angabe eines Namespace (weltweit) eindeutig gemacht werden. Bei den bisherigen XSD-Beispielen wurde auf die Verifizierung eines Namespace verzichtet. Um den Namespace des Ziel-XML-Dokumentes zu berücksichtigen (hier war dies http://my-domain.com/Person) muss für ein XSD-Dokument ein Target-Namespace festgelegt werden. Um diesen Namespace für Datentypen innerhalb des XML Schemas zu verwenden, muss außerdem ein Namespace-Präfix für den Target-Namespace festgelegt werden. Es muss auch festgelegt werden, dass nur qualifizierte Elemente-Namen (ElementeNamen für die ein Namespace festgelegt wurde) akzeptiert werden. <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://my-domain.com/Person" xmlns:typesns="http://my-domain.com/Person" elementFormDefault="qualified"> ... 3 1.3.4 XML-Dokumente mit XML Schema Um ein XML-Dokument gegen ein XML Schema validieren zu können, muss der Ort des Schemas in der XML-Datei angegeben werden. Dafür sind zwei Attribute interessant, die aus dem Namespace http://www.w3.org/2001/XMLSchema-instance (Präfix: xsi) hervorgehen: xsi:noNamespaceSchemaLocation und xsi:schemaLocation. Bei Verwendung des Attributs xsi:noNamespaceSchemaLocation wird der Namespace bei der Validierung nicht berücksichtigt. Bei Verwendung des Attributs xsi:schemaLocation wird der Namespace bei der Validierung berücksichtigt und muss entsprechend angegeben werden. Im Folgenden werden die beiden Dateien Person.xml und Person.xsd dargestellt. XML Schema (Person.xsd) <?xml version="1.0" encoding="UTF-8"?> <xsd:schema targetNamespace="http://my-domain.com/Person" xmlns:typesns="http://my-domain.com/Person" xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> <xsd:element name="Person" type="typesns:PersonType"/> <xsd:complexType name="PersonType"> <xsd:sequence> <xsd:element name="Name" type="xsd:string"/> <xsd:element name="Adresse" type="xsd:string"/> <xsd:element name="Telefon" type="typesns:TelefonType"/> </xsd:sequence> </xsd:complexType> <xsd:simpleType name="TelefonType"> <xsd:restriction base="xsd:token"> <xsd:pattern value="…"/> </xsd:restriction> </xsd:simpleType> </xsd:schema> XML Schema Instanz (Person.xml) <?xml version="1.0" encoding="UTF-8"?> <Person xmlns="http://my-domain.com/Person" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://my-domain.com/Person Person.xsd"> <Name>Max Mustermann</Name> <Adresse>Hauptstr. 1, 01234 Irgendwo</Adresse> <Telefon>+49/321/123456-100</Telefon> </Person> In diesem Beispiel wird bei der Validierung der Namespace mit berücksichtigt. Befinden sich außerdem beide Dateien im selben Verzeichnis, ist es nicht nötig den Pfad der XSD-Datei explizit festzulegen. 4 1.4 Verarbeitung von XML Nachdem im vorhergehenden Kapitel die Struktur von XML dargestellt wurde, wie sie der Mensch sieht, wird in diesem Kapitel auf die Verarbeitung von XML-Dateien durch die Maschine eingegangen. 1.4.1 DOM DOM steht für Document Object Model. DOM ist schon seit langen aus der xHTML-Welt bekannt. Dort dient DOM zum dynamischen Ändern von HTML-Seiten mit Hilfe von JavaScript-Funktionen. DOM ist also eine API, die festlegt, wie auf xHTML-Dokumente und XML-Dokumente zugegriffen werden kann, und wie sie verändert werden können. Das zentrale Element bei DOM ist der Knoten (Node). Durch Hinzufügen von Knoten zu einem bereits existierenden (Root-) Knoten kann eine beliebige Baumstruktur erstellt werden. Auf XML angewendet bedeutet dies, dass jedes Element ein Knoten vom Typ Element ist. Das Beispiel aus dem vorhergehenden Abschnitt kann also auch als Baumstruktur dargestellt werden. Document>#document + Element>Person Attr>xmlns:myns=http://my-domain.com/Person Attr>xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance Attr>xsi:noNamespaceSchemaLocation=Person.xsd + Element>Name + Text>#text=Max Mustermann + Element>Adresse + Text>#text=Hauptstr. 1, 01234 Irgendwo + Element>Telefon + Text>#text=+49/321/123456-100 Neben dem Knotentyp Element gibt es in DOM noch 11 weiter Kontentypen. Drei davon sind ebenfalls in der Baumdarstellung enthalten: der Dokumentknoten (Document), Attributknoten (Attr) und Textknoten (Text). Textknoten sind besonders tückisch, da sie sich zwischen die Tags schleichen und oft nicht zum Inhalt gehören, sondern dafür sorgen, dass das Dokument ‚schön’ gelesen werden kann. XML-Editoren bieten dafür meist die Funktion Pretty-Print an. Um diese Formatierungen (hauptsächlich sind das zusätzliche Leerzeichen, Tabulatoren und Zeilenumbrüche) wieder zu entfernen, kann das XML-Dokument ‚normalisiert’ (normalize) werden. Normalize ist sozusagen das Gegenteil zu Pretty Print. Das XML-Dokument besteht dann aus nur einer Zeile – was das Lesen für den Menschen erschwert. Mit Programmiersprachen oder Frameworks, die sich an die DOM-Spezifikation halten, kann dank der DOM-API in ähnlicher Weise auf XML-Strukturen zugegriffen werden. Das wird im folgenden Beispiel deutlich. Da wird die XML-Baumstruktur des obigen Beispiels einmal mit JavaScript-Befehlen und zum anderen mit Java-Befehlen erstellt. Beeindruckend ist, dass obwohl beide Sprachen außer dem Namen (‚Java’) nicht viel gemein haben, der Quellcode aufgrund der DOM-API fast identisch ist. 5 JavaScript var root = xmldoc.createElement("Person"); root.setAttribute("xmlns","http://my-domain.com/Person"); var name = xmldoc.createElement("Name"); name.appendChild(xmldoc.createTextNode("Max Mustermann")); root.appendChild(name); var adresse = xmldoc.createElement("Adresse"); adresse.appendChild(xmldoc.createTextNode("Hauptstr. 1, 01234 Irgendwo")); root.appendChild(adresse); var telefon = xmldoc.createElement("Telefon"); telefon.appendChild(xmldoc.createTextNode("+49/321/123456-100")); root.appendChild(telefon); xmldoc.appendChild(root); Java Element root =xmldoc.createElement("Person"); root.setAttribute("xmlns","http://my-domain.com/Person"); Element name = xmldoc.createElement("Name"); name.appendChild(xmldoc.createTextNode("Max Mustermann")); root.appendChild(name); Element adresse = xmldoc.createElement("Adresse"); adresse.appendChild(xmldoc.createTextNode("Hauptstr. 1, 01234 Irgendwo")); root.appendChild(adresse); Element telefon = xmldoc.createElement("Telefon"); telefon.appendChild(xmldoc.createTextNode("+49/321/123456-100")); root.appendChild(telefon); xmldoc.appendChild(root); Ein Vorteil von DOM ist, dass nach dem Parse-Vorgang zu jeder Zeit auf alle Knoten des Dokumentes zugegriffen werden kann. Das ist möglich, da der Parser das gesamte Dokument zunächst in den Hauptspeicher lädt. Bei großen XML-Dokumenten kann dies jedoch zu starken Performanz-Problemen führen. 1.4.2 SAX SAX steht für Simple API for XML. Wird eine XML-Datei von einem SAX-Parser eingelesen, so werden Ereignisse geworfen. Im Wesentlichen gibt es fünf Ereignisse: Start eines Dokumentes, Ende eines Dokumentes, Start eines Elementes, Ende eines Elementes und Text eingelesen. Diese Ereignisse veranlassen den Parser im zugehörigen ContentHandler die entsprechenden Methoden aufzurufen. public public public public public void void void void void startDocument(); endDocument(); startElement(...); endElement(...); characters(...); Wird die bereits mehrfach als Beispiel verwendete Datei Person.xml als Stream eingelesen (<Person><Name>Max Mustermann</Name><Adresse>Hauptstr. 1, ...), so werden nacheinander die folgenden Events geworfen: startDocument – startElement>Person – startElement>Name – characters>Max Mustermann – endElement>Name – ... 6 Dadurch, dass die Informationen bereits beim Parse-Vorgang zu Verfügung gestellt werden und nicht erst nachdem der XML-Baum im Speicher erstellt wurde, ist SAX im Allgemeinen schneller als DOM und braucht weniger Speicher. Besonders bei großen XML-Dateien, die evtl. noch Binärdaten, wie Bilder, enthalten, ist die Verwendung von SAX sehr zu empfehlen. Der Nachteil ist jedoch, dass Knoten-Informationen, die zu Beginn des Parse-Vorgangs entstehen und im weiteren Verlauf des Parsens noch benötigt werden, in Variablen zwischengespeichert werden müssen. 1.4.3 JAXP Derzeit gibt es eine Vielzahl an open source XML-Parsern: JDOM, DOM4J und Xerces-J – um nur einige zu nennen. Alle unterstützen sowohl DOM-, als auch SAX-Parsing – zumal DOM-Parser im Hintergrund sowieso meist SAX-Parser verwenden. Jeder Parser hat sicher seine Daseinsberechtigung, sei es aufgrund besserer Performanz, einfacher Bedienung oder größerem Funktionsumfang. Genau diese Gründe können jedoch dazu führen, den Parser je nach Bedarf zu wechseln. Um nicht jedes Mal den gesamten Quellcode anpassen zu müssen, ist es wünschenswert, eine Schnittstelle (API) zu haben, die alle der Parser unterstützen. JAXP steht für Java API for XML Processing und ist genau diese Schnittstelle, bestehend aus Interfaces und abstrakten Klassen, die JAXP-konforme Parser implementieren müssen. Werden die Parser nur über JAXP gesteuert, ist es möglich einen JAXP-konformen Parser durch einen anderen zu ersetzen, ohne den Quellcode zu ändern. Die Verwendung des Parsers muss dem JAXP Framework lediglich mitgeteilt werden. Dies geschieht z. B. mit dem Befehl java -Djavax.xml.parsers.SAXParserFactory = org.apache.xerces.jaxp.SAXParserFactoryImpl In der Praxis ist ein Parsertausch oft dennoch schwierig, da der Funktionsumfang, also die Funktionen, die zusätzlich zu JAXP vom Parser angeboten werden, meist als Kriterium für die Parserwahl genommen wird und der andere Parser diese Funktion dann nicht (in der selben Form) unterstützt. JAXP und DOM Mit dem folgenden Code wird die XML-Datei Person.xml mit einem DOM-Parser durch Verwendung der JAXP-Schnittstelle eingelesen. Die Validierung, also die Beachtung des XML Schemas Person.xsd, ist aktiviert. DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setAttribute( "http://java.sun.com/xml/jaxp/properties/schemaLanguage", "http://www.w3.org/2001/XMLSchema"); factory.setValidating(true); factory.setNamespaceAware(true); DocumentBuilder builder = factory.newDocumentBuilder(); Document document = builder.parse(new File("Person.xml")); 7 JAXP und SAX Mit dem folgenden Code wird die XML-Datei Person.xml mit einem SAX-Parser, durch Verwendung der JAXP-Schnittstelle eingelesen. SAXParserFactory factory = SAXParserFactory.newInstance(); factory.setValidating(true); factory.setNamespaceAware(true); SAXParser saxParser = factory.newSAXParser(); saxParser.parse( new File("Person.xml"), new DefaultHandler()); JAXP und XSLT XSLT steht für eXtensible Stylesheet Language for Transformations und ist eine XMLbasierte Sprache, mit der XML-Dateien in andere textbasierte Dateien umgewandelt werden können. Als Eingabe wird immer XML erwartet, die Ausgabe kann ein beliebiger Text sein (z. B. auch XML). In einer XSLT-Datei (oder XSL-Stylesheet), ebenfalls eine XML-Datei, werden die Umwandlungsregeln festgelegt. Der Transformer ändert die Quell-XML-Datei entsprechend der Regeln des Stylesheets zu einem neuen Text. Im Quell-XML-Dokument muss eine Referenz auf ein Stylesheet angegeben sein. Dies erfolgt mit der folgenden Zeile. <?xml-stylesheet type="text/xsl" href="xyz.xsl"?> Wird kein Stylesheet angegeben, ist das Ergebnis gleich der Quelle. Das ist z. B. dann sinnvoll, wenn ein im Speicher befindlicher DOM-Tree (auch SAX-Events oder Sreams sind möglich) in eine (XML-) Datei im Filesystem transformiert werden soll. JAXP konforme Parser müssen ebenfalls einen Transformer bereitstellen. Das folgende CodeBeispiel zeigt, wie mit JAPX ein Transformer erstellt und der Transform-Vorgang ausgeführt wird. TransformerFactory factory = TransformerFactory.newInstance(); Transformer transformer = factory.newTransformer(); transformer.transform(source,result); 8 2 WSDL 2.1 Was ist WSDL WSDL steht für Web Service Description Language. WSDL-Dokumente sind XMLDokumente, die die Schnittstelle eines Web Service beschreiben. Das heißt, ein WSDLDokument beinhaltet Informationen darüber, wo der Service im Web zu finden ist, welche Operationen (Methoden) er zu Verfügung stellt und wie auf diese Operationen zugegriffen werden kann. Es ist also sinnvoll eine WSDL-Datei öffentlich zugänglich zu machen. Dafür gibt es drei Möglichkeiten: Jeder Web Service bietet die Möglichkeit, seine Schnittstelle durch Angabe eines URLParameters (z. B. ?wsdl bei Axis) einzusehen. Die Schnittstellenbeschreibungsdatei mit der Endung .wsdl kann im Web zu Verfügung gestellt werden (z. B. in einem LDAP- oder FTP-Verzeichnis). Ein Schnittstellenbeschreibungstemplate wird in Form eines tModel von einem UDDI(Universal Description, Discovery and Integration) Verzeichnisserver für einen oder mehrere Services veröffentlicht. Ein tModel ist demnach eine WSDL-Beschreibung für eine Gruppe von Web Services (eine Art Interface), die festlegt, was ein Web Service dieser Gruppe mindestens bereitstellen muss. 2.2 Aufbau von WSDL-Dokumenten WSDL liegt zurzeit in der Version 2.0 vor. Diese Version ist sehr viel mächtiger als ihre Vorgänger. Jedoch implementieren die wenigsten freien Tools zum jetzigen Zeitpunkt diese Funktionalität. Deshalb wird in den Tutorials WSDL der Version 1.1 verwendet. Natürlich kann auch solch eine WSDL-Datei sehr komplex werden – wir beschränken uns hier auf das notwendigste. WSDL 1.1 besteht in der Grundstruktur, neben dem Root-Element <definitions>, aus sechs Hauptelementen (genaue Informationen können der Spezifikation entnommen werden http://www.w3.org/TR/wsdl): <types> – enthält Inline Schemas (sozusagen den Inhalt von XSD-Dateien innerhalb des WSDL-XML-Dokuments) <message> – eine abstrakte Definition des Inhalts der Nachrichten, die zwischen Web Service und Web Service Client ausgetauscht werden <portType> – eine Sammlung von Operationen (Web Service Methoden) einer oder mehrerer Endpunkte <binding> – beinhaltet Details zu Protokollinformationen (HTTP, SOAP, …) und zum Nachrichteninhalt <port> – besser Endpoint, repräsentiert eine bestimmte URL für ein Binding <service> – eine Sammlung von zugehörigen Ports (Endpoints) 9 Eine korrekte WSDL-Datei, hier für einen Web Service Calculator mit der Methode add, kann demnach folgendermaßen aussehen. <?xml version="1.0" encoding="UTF-8"?> <wsdl:definitions targetNamespace="http://Calculator/" xmlns:ns="http://Calculator/" xmlns:typesns="http://Calculator/Types" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <wsdl:types> <xsd:schema targetNamespace="http://Calculator/Types"> <xsd:complexType name="addRequestType"> <xsd:sequence> <xsd:element name="a" type="xsd:long"/> <xsd:element name="b" type="xsd:long"/> </xsd:sequence> </xsd:complexType> <xsd:complexType name="addResponseType"> <xsd:sequence> <xsd:element name="addReturn" type="xsd:long"/> </xsd:sequence> </xsd:complexType> <xsd:element name="addRequestMessagePart" type="typesns:addRequestType"/> <xsd:element name="addResponseMessagePart" type="typesns:addResponseType"/> </xsd:schema> </wsdl:types> <wsdl:message name="addRequestMessage"> <wsdl:part name="addRequestMessagePart" element="typesns:addRequestMessagePart"/> </wsdl:message> <wsdl:message name="addResponseMessage"> <wsdl:part name="addResponseMessagePart" element="typesns:addResponseMessagePart"/> </wsdl:message> <wsdl:portType name="Calculator"> <wsdl:operation name="add"> <wsdl:input name="addInputElement" message="ns:addRequestMessage"/> <wsdl:output name="addOutputElement" message="ns:addResponseMessage"/> </wsdl:operation> </wsdl:portType> <wsdl:binding name="CalculatorSoapBinding" type="ns:Calculator"> <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/> <wsdl:operation name="add"> <soap:operation soapAction="http://Calculator/add"/> <wsdl:input name="addInputElement"> <soap:body use="literal"/> </wsdl:input> <wsdl:output name="addOutputElement"> <soap:body use="literal"/> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="CalculatorService"> <wsdl:port name="Calculator" binding="ns:CalculatorSoapBinding"> <soap:address location="http://www.my-domain.com/Calculator/services/Calculator"/> </wsdl:port> </wsdl:service> </wsdl:definitions> 10 3 SOAP 3.1 Was ist SOAP SOAP ist ein Protokoll zum Übertragen von XML-Nachrichten über das Netzwerk. SOAP ist der Nachfolger von XML-RPC. Hier wird deutlich, dass es sich bei diesem Protokoll primär um ein Protokoll für die Ausführung von Remote Procedure Calls handelt. Meist wird für die Übertragung das HTTP-Protokoll als Transport-Protokoll verwendet. Prinzipiell ist jedoch jedes Protokoll denkbar, das in der Lage ist ASCII-Zeichen als Payload (z. B. in Form von MIME-Attachments) zu Übertragen. So wäre also auch SMTP möglich. SOAP stand ursprünglich für Simple Object Access Protocol. Seit der Version 1.2 steht es nur noch für SOAP, denn ‚Simple’ ist es nun nicht mehr. 3.2 Aufbau von SOAP Eine SOAP-Nachricht besteht aus dem Root-Element <Envelope> und ähnlich wie ein HTML-Dokument aus einem optionalen Header- und einem Body-Element. Das HeaderElement beinhaltet anwendungsspezifische Informationen, wie Informationen zu Transaktionen, Sicherheit o. ä. Das Body-Element beinhaltet den eigentlichen RPC. Bei einem korrekten Request-Response-Szenario, angewendet auf unser obiges Beispiel, könnten folgende Nachrichten übertragen werden. Request <?xml version="1.0" encoding="UTF-8"?> <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <soapenv:Body> <addRequestMessagePart xmlns="http://Calculator/Types"> <a xmlns="">7</a> <b xmlns="">5</b> </addRequestMessagePart> </soapenv:Body> </soapenv:Envelope> Response <?xml version="1.0" encoding="utf-8"?> <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <soapenv:Body> <addResponseMessagePart xmlns="http://Calculator/Types"> <addReturn xmlns="">12</addReturn> </addResponseMessagePart> </soapenv:Body> </soapenv:Envelope> 11 4 Axis Dieses Kapitel dient dazu, die spätere Projektstruktur nachvollziehen zu können. Wenn es Probleme geben sollte, die Beispiele zu implementieren, ist das nicht schlimm, denn die Implementierung wird in den Tutorials meist automatisch bzw. durch Wizards geschehen. 4.1 Was ist Axis Axis steht für Apache eXtensible Interaction System und ist das Nachfolgeprojekt von Apache SOAP. Die Axis Engine ist also eine Open Source Implementierung der W3C Spezifikation SOAP. 4.2 Web Services mit Axis Die Axis Engine fungiert als ein Servlet, das in einem Servlet-Container (z. B. Tomcat) geschoben wird. In dieses Servlet können nun Web Services integriert werden. Es gibt verschiedene Möglichkeiten Web Services mit Axis zu nutzen, die in den nächsten Abschnitten näher betrachtet werden. Die Installation von Axis ist relativ einfach. Nach dem Herunterladen des Archivs Axis_1.X.jar wird der im Ordner WebApps des Archivs enthaltene Ordner axis in den Ordner WebApps von Tomcat geschoben. Anschließend müssen die folgenden Dateien in der Umgebungsvariable CLASSPATH in ihrer entsprechenden Version festgelegt werden: axis.jar, jaxrpc.jar, saaj.jar, commons-logging.jar, commons-discovery.jar, wsdl4j.jar. Nach der Installation kann der Tomcat gestartet werden und mit der URL http://localhost/axis/ wird die Axis-Startseite aufgerufen. Der Link Validation zeigt, ob alle nötigen Archive verfügbar sind. Der Link List zeigt eine Liste der unter Axis deployten Web Services. 4.2.1 Web Services erstellen als Java Web Service (jws) Die einfachste Variante zum Veröffentlichen von Web Service Methoden im Web ist die Implementierung einer Java Web Service Klasse (.jws). public class Calculator { public long add(long a, long b) { return a+b; } } Nach der Installation von Axis wird die Web Service Klasse Calculator.jws in den Ordner <TOMCAT_HOME>\WebApps\axis verschoben. Unter der URL http://localhost/axis/Calculator.jws kann der Service getestet werden (z. B. mit den Parametern: ?method=add&a=5&b=7). Diese Variante der Web Service Publikation bietet nur geringe Anpassungsmöglichkeiten. Es werden zum Beispiel alle Methoden die public sind als Operationen angeboten. Das ist nicht immer gewünscht. 12 4.2.2 Web Service erstellen mit WSDD WSDD steht für Web Service Deployment Descriptor. Das Deployment dient der Installation des Web Service auf dem SOAP-Router. Durch das Deployment können Eigenschaften festgelegt werden, die der Web Service zur Laufzeit besitzen soll. Diese Eigenschaften werden in einer XML-Datei, dem Web Service Deployment Descriptor (WSDD), festgelegt. So kann zum Beispiel ein anderer als der Klassenname als Web Service Name festgelegt werden (genauere Informationen können den Dokumentationen von Axis unter http://ws.apache.org/axis/java/index.html entnommen werden). Für das obige Beispiel kann ein solcher Deskriptor den folgenden Aufbau haben. <deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"> <service name="CalculatorService" provider="java:RPC"> <parameter name="className" value="calculator.Calculator"/> <parameter name="allowedMethods" value="add"/> </service> </deployment> Wenn es einen Deployment Deskriptor (deploy.wsdd) zur Installation eines Web Service gibt, dann gibt es auch einen Undeployment Deskriptor (undeploy.wsdd), um einen Web Service wieder vom Server zu entfernen. <undeployment xmlns="http://xml.apache.org/axis/wsdd/"> <service name="CalculatorService" /> </undeployment> Der Parameter className im Deployment Deskriptor zeigt, dass es eine Klasse Calculator.class im Ordner (Package) calculator geben muss. Angelehnt an das Beispiel hat die Klasse den folgenden Inhalt. package calculator; public class Calculator { public long add(long a, long b) { return a+b; } } Alle kompilierten Klassen müssen bei Axis im Ordner WEB-INF\classes verfügbar sein. Deshalb wird der Ordner calculator zusammen mit der Klasse Calculator.class und den beiden Deskriptoren in den Ordner classes von Axis verschoben. Zum Deployen (bzw. Undeployen) wird der Axis AdminClient verwendet. Mit dem Konsolenaufruf java org.apache.axis.client.AdminClient deploy.wsdd -p80 aus dem Ordner calculator heraus wird der Web Service auf den Server deployt. 13 Der Service ist nun in Axis in der Liste der deployten Web Services aufgelistet (http://localhost/axis/servlet/AxisServlet) und kann über die URL http://localhost/axis/services/CalculatorService angesprochen werden. 4.2.3 Web Service erstellen als Web Applikation Wenn eigene Web Services geschrieben werden, ist es unter Umständen wünschenswert, diese von der Axis-Umgebung zu trennen – also ‚standalone’ zu betreiben. Das hat den Vorteil, dass so erstellte Archive, unabhängig von einer Axis-Installation, auf jedem anderen (Tomcat) Server lauffähig sind. In den Tutorials wird diese Variante verwendet. Bei genauer Betrachtung der Axis Web Applikation fällt auf, dass die Ordner der Anwendung einer bestimmten Struktur folgen. Der Root-Ordner ist der Name der Applikation (bzw. des Projektes) – in diesem Fall axis. Im Ordner axis gibt es einen Unterordner WEB-INF, der wiederum zwei Unterordner classes und lib besitzt. Im Ordner classes befinden sich die Quelldateien der Web Services. Im Ordner lib die Web Bibliotheken, die für die Ausführung der Services benötigt werden. Werden eigene Web Applikationen erstellt, müssen diese ebenfalls diese Ordnerstruktur aufweisen. Für den Web Service Calculator wäre das dann z. B. die folgende: CalculatorWebApp\WEB-INF\(classess,lib). In den Ordner classes muss der Ordner calculator mit der Klasse Calculator.class hineinkopiert werden, der weiter oben im Tutorial bereits implementiert wurde. In den Ordner lib müssen sämtliche Bibliotheken aus dem Ordner lib der axis-Anwendung hineinkopiert werden. In den WEB-INF-Ordner müssen zusätzlich noch zwei Dateien: zum einen der Deployment Deskriptor (allerdings muss der Dateiname zu server-config.wsdd geändert werden) und die Datei web.xml, die Servlet Deklarations- und Mapping-Informationen zum Axis-Servlet enthält. Die Datei web.xml kann ebenfalls aus dem Verzeichnis axis\WEB-INF kopiert werden. Der Web Service ist nun unter der folgenden http://localhost/CalculatorWebApp/services/CalculatorService. URL zu erreichen: Im obigen Beispiel wurde eine ‚Exploded Web Application’ erstellt. Das bedeutet, dass es sich um ein entpacktes WAR-Archiv handelt. Andersherum gesehen kann die erstellte Ordnerstruktur natürlich auch in einem WAR-Archiv zusammengefasst werden. Ein WARArchiv ist hier eine Zip-Datei mit der Endung .war. Ein Undeployment Deskriptor ist für das Web Archiv nicht nötig, da der Web Service bei jedem Start von Tomcat (re)deployed wird und falls die Dateien des Service nicht mehr verfügbar sind, wird er auch nicht deployt. Um also einen Service vom Server zu entfernen, reicht es das Verzeichnis der ‚Exploded Web Application’ und ggf. das zugehörige WARArchiv aus dem Tomcat WebApps-Verzeichnis zu löschen. In den Tutorials werden die Struktur und die Deskriptoren automatisch erzeugt, da Eclipse entsprechende Dynamic Web Projects zu Verfügung stellt. Das Deployen erfolgt mit Hilfe von Wizards, genau wie das Erstellen des WAR-Archivs. Der Programmierer braucht sich also um die bisher genannten Konventionen wenig Gedanken zu machen. 14 4.3 Axis und WSDL Axis ist in der Lage aus Java-Klassen eine WSDL-Datei und aus einer WSDL-Datei ein JavaKlassen-Gerüst zu generieren. Dafür werden die beiden Tools Java2WSDL und WSDL2Java verwendet. 4.3.1 Java2WSDL Java2WSDL wurde weiter oben bereits angewendet. Mit dem Parameter ?wsdl der Web Service URL wurde die Web Service Beschreibungsdatei im Browser angezeigt. Existieren bereits die Klassen eines Web Service bzw. ein Java-Interface, kann mit Java2WSDL die zugehörige WSDL-Datei manuell erstellt werden. Dazu wird auf der Konsole z. B. der folgende Befehl verwendet. java org.apache.axis.wsdl.Java2WSDL -l http://localhost/CalculatorWebApp/services/CalculatorService -n http://calculator calculator.Calculator Dieser Aufruf generiert die Datei CalculatorService.wsdl. Der Parameter –l gibt hierbei die URL an, unter der der Web Service später zu erreichen ist. Der Parameter –n gibt den Target-Namespace für die WSDL-Beschreibung an. calculator.Calculator ist der Klassenname. 4.3.2 WSDL2Java Existiert bereits eine WSDL-Beschreibung, sei es aufgrund eines existierenden Web Services bzw. in Form einer WSDL-Datei, so kann aus dieser Beschreibung ein Java-Klassengerüst erstellt werden. Beim Aufruf von WSDL2Java gibt es die Möglichkeit einen Client (eine Art SOAP-Proxy), bzw. einen Server (den Web Service) zu erstellen. Dies geschieht durch die Angabe der Parameter --client-side bzw. --server-side. Zum Erstellen des Web Service Calculator aus dem obigen Beispiel wird auf der Konsole der folgende Aufruf gestartet. java org.apache.axis.wsdl.WSDL2Java --server-side --skeletonDeploy true CalculatorService.wsdl Im Ordner calculator (Package-Name) wurden einige Dateien erstellt, die nun etwas genauer betrachtet werden. Calculator – das Service-Interface mit allen abstrakten Methoden, die der Web Service zu Verfügung stellt CalculatorService – eine intern verwendete Klasse um konform zur JAX-RPC- Spezifikation von SUN zu sein CalculatorServiceSoapBindingSkeleton – befindet sich zwischen der Axis Engine und der eigentlichen Web Service Implementierung 15 CalculatorServiceSoapBindingImpl – die eigentliche Implementierung der Web Service Operationen (Web Service Methoden) CalculatorServiceLocator – wird nur für den Client benötigt (nicht für den Server); liefert die Service-Instanz CalculatorServiceSoapBindingStub – wird nur vom Client verwendet; setzt Java Web Service Anfragen auf SOAP-Requests um Existieren komplexe Datentypen werden für diese außerdem gesonderte Klassen erstellt. deploy.wsdd / undeploy.wsdd – Deskriptoren zum (un)deployen (siehe Kapitel 4.2.2) Die Methode(n) der Klasse CalculatorServiceSoapBindingImpl implementiert werden. Im obigen Beispiel wäre das die Methode add. muss noch Bleibt die Frage: Warum so umständlich, wenn es auch einfach geht (siehe Kapitel 4.2)? Der Hintergrund ist der, dass die Anwendungslogik vom Zugriff getrennt sein sollte. Der Zugriff könnte statt über SOAP auch über HTTP- oder MIME-Bindings erfolgen. Die Funktionalität wäre in allen Fällen dieselbe. Wie auch immer, bei der Generierung der Klassen aus der WSDL-Beschreibung heraus wird immer diese Struktur eingehalten. Für das Erstellen der Web Services in den Tutorials ist jedoch nur die Klasse XXXBindingImpl interessant, da hier die eigentliche Funktionalität implementiert wird. 16