Apache Axis
Java Web Service (JWS)
Java Web Service Client
Web Services Deployment Descriptor (WSDD)
die SOAP Engine der Apache Group
Version 1.1, 2003, aus IBMs SAOP4J hervorgegangen
Standalone und Servlet Versionen
unterstützt SOAP 1.1 und 1.2
umfangreiche WSDL Unterstützung
Erzeugen von WSDL SOAP-Requests
Parsen der WSDL SOAP-Responses und Erzeugen entsprechender Java Objeke
Erzeugen von WSDL Beschreibungen aus Java Klassen
Erzeugen von Java Klassen(skeletons) aus WSDL Beschreibungen
Interfaces und Klassen in org.apache.axis
Verwendet JAX-RPC (javax.xml.rpc
)
die SOAP Nachrichten werden durch
org.apache.axis.Message
Objekte representiert
automatisches Deployment und (De-)serialisierung von Java Beans mit Java Web Service (JWS)
HTTP und JMS Transport
ein TCP-Monitor zur Analyse der SOAP Nachrichten
von Sun gibt es ein "Web Service Development Package", das vergleichbares zu Axis enthält
Dateien mit der Endung .jws
,
die eine JavaBean implementieren, können sofort
als Web Service verwendet werden
jws-Dateien werden auf das Axis Servlet gemapped
eine JavaBean verlangt im wesentlichen einen Konstruktor
ohne Argumente und die Zugriffsmethoden müssen als
getXXX()
bzw. setXXX()
implementiert sein
Ein einfacher Java Web Service: CarStore.jws
public class CarStore { private static String[] cars = null; public CarStore() { if ( cars != null ) { return; } cars = new String[] { "Opel", "Porsche", "BMW", "Audi", "VW", "Mazda", "Toyota", "Volvo" }; } public String getCar( int iCar ) { if ( cars == null ) { return "uninitialized"; } if ( iCar < 0 || cars.length <= iCar ) { return "out of bounds"; } return cars[ iCar ]; } public String getCars( ) { if ( cars == null ) { return "uninitialized"; } StringBuffer result = new StringBuffer(); for ( int i = 0; i < cars.length; i++ ) { result.append(" " + cars[i] ); } return result.toString(); } public String[] getCarArray( ) { if ( cars == null ) { return new String[] { "uninitialized" }; } return cars; } public void setAppendCar(String car) { String[] newCars = new String[ cars.length + 1]; for ( int i = 0; i < cars.length; i++ ) { newCars[i] = cars[i]; } newCars[ newCars.length -1 ] = car; cars = newCars; return; } }
Das AxisServlet stellt mit dem Parameter wsdl
(der Aufruf URL ist CarStor.jws?wsdl
)
folgende WSDL Beschreibung des Service zur Verfügung:
<?xml version="1.0" encoding="UTF-8"?> <wsdl:definitions targetNamespace="http://localhost:8080/axis/CarStore.jws" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:apachesoap="http://xml.apache.org/xml-soap" xmlns:impl="http://localhost:8080/axis/CarStore.jws" xmlns:intf="http://localhost:8080/axis/CarStore.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> <schema targetNamespace="http://localhost:8080/axis/CarStore.jws" xmlns="http://www.w3.org/2001/XMLSchema"> <import namespace="http://schemas.xmlsoap.org/soap/encoding/"/> <complexType name="ArrayOf_xsd_string"> <complexContent> <restriction base="soapenc:Array"> <attribute ref="soapenc:arrayType" wsdl:arrayType="xsd:string[]"/> </restriction> </complexContent> </complexType> </schema> </wsdl:types> <wsdl:message name="getCarResponse"> <wsdl:part name="getCarReturn" type="xsd:string"/> </wsdl:message> <wsdl:message name="setAppendCarResponse"> </wsdl:message> <wsdl:message name="getCarArrayRequest"> </wsdl:message> <wsdl:message name="setAppendCarRequest"> <wsdl:part name="car" type="xsd:string"/> </wsdl:message> <wsdl:message name="getCarsRequest"> </wsdl:message> <wsdl:message name="getCarRequest"> <wsdl:part name="iCar" type="xsd:int"/> </wsdl:message> <wsdl:message name="getCarArrayResponse"> <wsdl:part name="getCarArrayReturn" type="impl:ArrayOf_xsd_string"/> </wsdl:message> <wsdl:message name="getCarsResponse"> <wsdl:part name="getCarsReturn" type="xsd:string"/> </wsdl:message> <wsdl:portType name="CarStore"> <wsdl:operation name="getCar" parameterOrder="iCar"> <wsdl:input message="impl:getCarRequest" name="getCarRequest"/> <wsdl:output message="impl:getCarResponse" name="getCarResponse"/> </wsdl:operation> <wsdl:operation name="getCarArray"> <wsdl:input message="impl:getCarArrayRequest" name="getCarArrayRequest"/> <wsdl:output message="impl:getCarArrayResponse" name="getCarArrayResponse"/> </wsdl:operation> <wsdl:operation name="getCars"> <wsdl:input message="impl:getCarsRequest" name="getCarsRequest"/> <wsdl:output message="impl:getCarsResponse" name="getCarsResponse"/> </wsdl:operation> <wsdl:operation name="setAppendCar" parameterOrder="car"> <wsdl:input message="impl:setAppendCarRequest" name="setAppendCarRequest"/> <wsdl:output message="impl:setAppendCarResponse" name="setAppendCarResponse"/> </wsdl:operation> </wsdl:portType> <wsdl:binding name="CarStoreSoapBinding" type="impl:CarStore"> <wsdlsoap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> <wsdl:operation name="getCar"> <wsdlsoap:operation soapAction=""/> <wsdl:input name="getCarRequest"> <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://DefaultNamespace" use="encoded"/> </wsdl:input> <wsdl:output name="getCarResponse"> <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://localhost:8080/axis/CarStore.jws" use="encoded"/> </wsdl:output> </wsdl:operation> <wsdl:binding name="CarStoreSoapBinding" type="impl:CarStore"> <wsdlsoap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> <wsdl:operation name="getCar"> <wsdlsoap:operation soapAction=""/> <wsdl:input name="getCarRequest"> <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://DefaultNamespace" use="encoded"/> </wsdl:input> <wsdl:output name="getCarResponse"> <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://localhost:8080/axis/CarStore.jws" use="encoded"/> </wsdl:output> </wsdl:operation> <wsdl:operation name="getCarArray"> <wsdlsoap:operation soapAction=""/> <wsdl:input name="getCarArrayRequest"> <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://DefaultNamespace" use="encoded"/> </wsdl:input> <wsdl:output name="getCarArrayResponse"> <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://localhost:8080/axis/CarStore.jws" use="encoded"/> </wsdl:output> </wsdl:operation> <wsdl:operation name="getCars"> <wsdlsoap:operation soapAction=""/> <wsdl:input name="getCarsRequest"> <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://DefaultNamespace" use="encoded"/> </wsdl:input> <wsdl:output name="getCarsResponse"> <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://localhost:8080/axis/CarStore.jws" use="encoded"/> </wsdl:output> </wsdl:operation> <wsdl:operation name="setAppendCar"> <wsdlsoap:operation soapAction=""/> <wsdl:input name="setAppendCarRequest"> <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://DefaultNamespace" use="encoded"/> </wsdl:input> <wsdl:output name="setAppendCarResponse"> <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://localhost:8080/axis/CarStore.jws" use="encoded"/> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="CarStoreService"> <wsdl:port binding="impl:CarStoreSoapBinding" name="CarStore"> <wsdlsoap:address location="http://localhost:8080/axis/CarStore.jws"/> </wsdl:port> </wsdl:service> </wsdl:definitions>
mit dem Aufruf CarStore.jws?method=getCar&x=0
erhält man folgende Antwort
<?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> <getCarResponse soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <getCarReturn xsi:type="xsd:string">Opel</getCarReturn> </getCarResponse> </soapenv:Body> </soapenv:Envelope>
mit dem Aufruf CarStore.jws?method=getCars
erhält man folgende Antwort
<?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> <getCarsResponse soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <getCarsReturn xsi:type="xsd:string"> Opel Porsche BMW Audi VW Mazda Toyota Volvo </getCarsReturn> </getCarsResponse> </soapenv:Body> </soapenv:Envelope>
mit dem Aufruf CarStore.jws?method=getCarArray
erhält man folgende Antwort
<?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> <getCarArrayResponse soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <getCarArrayReturn xsi:type="soapenc:Array" soapenc:arrayType="xsd:string[8]" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"> <item>Opel</item> <item>Porsche</item> <item>BMW</item> <item>Audi</item> <item>VW</item> <item>Mazda</item> <item>Toyota</item> <item>Volvo</item> </getCarArrayReturn> </getCarArrayResponse> </soapenv:Body> </soapenv:Envelope>
mit dem Aufruf
CarStore.jws?method=setAppendCar&x=DaimlerChrysler
erhält man folgende Antwort
<?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> <setAppendCarResponse soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> </soapenv:Body> </soapenv:Envelope>
der Inhalt des Objekts CarStor schient sich aber nicht zu ändern
Einsatz der Klassen Service
und Call
aus dem Paket org.apache.axis.client
Ein einfacher Client, der aus dem CarStore WS, ein Auto ausliest: CarStoreGetCar
import java.io.IOException; import java.net.URL; import java.net.MalformedURLException; import java.rmi.RemoteException; import javax.xml.namespace.QName; import org.apache.axis.client.Call; import org.apache.axis.client.Service; import javax.xml.rpc.ServiceException; public class CarStoreGetCar { final static String carStoreUrl = "http://localhost:8090/axis/services/CarStore"; // or "http://localhost:8090/axis/CarStore.jws"; final static String operation = "getCar"; public static void main(String[] args) { Service service = new Service(); Integer carNo = new Integer( 2 ); Object[] params = new Object[] { carNo }; String answer = ""; try { URL url = new URL( carStoreUrl ); Call call = (Call) service.createCall(); call.setTargetEndpointAddress( url ); call.setOperationName( operation ); answer = (String) call.invoke( params ); System.out.println("gesuchtes Auto = " + answer); } catch(MalformedURLException e) { e.printStackTrace(); } catch(ServiceException e) { e.printStackTrace(); } catch(RemoteException e) { e.printStackTrace(); } } }
Wird axis/service/CarStore
angesprochen muss der Service mit WSDD (siehe unten)
beschrieben und deployed worden sein.
Wird axis/CarStore.jws
angesprochen, dann wurde der entsprechende Service
mit WSDD (siehe unten) automatisch beschrieben und deployed.
Die Ausgabe ist z.B.
gesuchtes Auto = BMW
Der Client erzeugt folgende SOAP Anfrage
<?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> <getCar soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <arg0 xsi:type="xsd:int">2</arg0> </getCar> </soapenv:Body> </soapenv:Envelope>
Der Web Service antwortet mit folgender SOAP Nachricht
<?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> <getCarResponse soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <getCarReturn xsi:type="xsd:string">BMW</getCarReturn> </getCarResponse> </soapenv:Body> </soapenv:Envelope>
Bei der Operation getCars
erzeugt der Client
folgenden SOAP Body in der Anfrage
<soapenv:Body> <getCars soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> </soapenv:Body>
und erhält folgende Antwort im SOAP Body
<soapenv:Body> <getCarsResponse soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <getCarsReturn xsi:type="xsd:string"> Opel Porsche BMW Audi VW Mazda Toyota Volvo</getCarsReturn> </getCarsResponse> </soapenv:Body>
Bei der Operation getCarArray
erzeugt der Client
folgenden SOAP Body in der Anfrage
<soapenv:Body> <getCarArray soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> </soapenv:Body>
Die Anfrage lässt sich genau so gut an JWS stellen, dabei wird der gleiche SOAP Body wie oben verwendet.
Die main-Methode ist wie folgt zu ändern:
final static String carStoreUrl = "http://localhost:8090/axis/CarStore.jws"; // "http://localhost:8090/axis/services/CarStore"; ... answer = (String[]) call.invoke( params ); System.out.println("gefundene Autos:"); for ( int i = 0; i < answer.length; i++ ) { System.out.println("Auto[" + i + "] = " + answer[i]); } ...
Die Antwort ist jetzt ein SOAP String Array
<soapenv:Body> <getCarArrayResponse soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <getCarArrayReturn xsi:type="soapenc:Array" soapenc:arrayType="xsd:string[8]" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"> <item>Opel</item> <item>Porsche</item> <item>BMW</item> <item>Audi</item> <item>VW</item> <item>Mazda</item> <item>Toyota</item> <item>Volvo</item> </getCarArrayReturn> </getCarArrayResponse> </soapenv:Body>
Die Ausgabe des Clients ist dann
gefundene Autos: Auto[0] = Opel Auto[1] = Porsche Auto[2] = BMW Auto[3] = Audi Auto[4] = VW Auto[5] = Mazda Auto[6] = Toyota Auto[7] = Volvo
Bei der Operation setAppendCar
erzeugt der Client
folgenden SOAP Body in der Anfrage
<soapenv:Body> <setAppendCar soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <arg0 xsi:type="xsd:string">Renault</arg0> </setAppendCar> </soapenv:Body>
Die Antwort ist leer, da es sich um eine void-Methode handelt, und sieht wie folgt aus
<soapenv:Body> <setAppendCarResponse soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> </soapenv:Body>
Fragt man dann mit CarStoreGetCarArray
den Inhalt
wieder ab, ergibt sich
gefundene Autos: Auto[0] = Opel Auto[1] = Porsche Auto[2] = BMW Auto[3] = Audi Auto[4] = VW Auto[5] = Mazda Auto[6] = Toyota Auto[7] = Volvo Auto[8] = Renault
Statische Variablen bleiben also wie gewohnt bis zum Neuladen der Klasse erhalten. Um Informationen dauerhaft zu speichern müssen Datenbanken, Preferences oder Dateien verwendet werden.
Zuordnung von Java Klassen zu WSDL Beschreibungen
JWS erzeugt automatisch WSDDs und deployed die Anwendung
für einen Service wird ein Name und ein Provider
in dem Element deployment
definiert
Provider (auch als Service Style bezeichnet) können z.B. RPC oder Message sein
der Service benötigt die Parameter className
und allowedMethods
className
definiert die Java Klasse,
die den Service leistet.
Die Klasse muss sich z.B. in axis/WEB-INF/classes
befinden.
allowedMethods
listet alle (public) Methoden, die
der Service nach aussen bereitstellen soll
die WSDD-Datei wird mit dem Tool
org.apache.axis.client.AdminClient
verarbeitet, das die entsprechenden Eintragungen
im Server vornimmt
Web Services bleiben über den Neustart von Tomcat hinweg deployed und verfügbar
die Service Objekte werden für jede Anfrage neu erzeugt, die Klassen werden nur bei Bedarf neu geladen, d.h. um Änderungen persistent zu speichern muss z.B. eine Datenbank verwendet werden
Sollen eigene Datentypen transportiert werden,
müssen mit dem service-Subelement typeMapping
die entsprechenden Zuordnungen vorgenommen werden:
Beispiel für den CarStore: CarStoreUnDeploy.wsdd.
Als Provider ist hier mit java:RPC
die RPC-artige Durchführung gewählt.
<?xml version="1.0" encoding="utf-8" ?> <deployment name="test" xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java" > <service name="CarStore" provider="java:RPC" > <parameter name="className" value="CarStore" /> <parameter name="allowedMethods" value="*" value="getCar getCars setAppendCar getCarArray" /> </service> </deployment>
Die Aktivierung sieht z.B. wie folgt aus:
java ... org.apache.axis.client.AdminClient CarStoreDeploy.wsdd Processing file CarStoreDeploy.wsdd <Admin>Done processing</Admin>
zum Entfernen eines Services gibt es einen Undeployment Descriptor
in dem Element undeployment
wird nur der Name des Service angegeben, der
entfernt werden soll
das name
Attribut
von service
spezifiziert
den Name des Web Services
eine Undeployment-WSDD-Datei wird ebenfalls mit dem Tool
AdminClient
verarbeitet
Beispiel CarStoreUnDeploy.wsdd
<?xml version="1.0" encoding="utf-8" ?> <undeployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java" > <service name="CarStore" /> </undeployment>
Die Deaktivierung sieht z.B. wie folgt aus:
java ... org.apache.axis.client.AdminClient CarStoreUnDeploy.wsdd Processing file CarStoreUnDeploy.wsdd <Admin>Done processing</Admin>
Grid Services im Grid Computing
Grid-WSDL (GWSDL)
© Universität Mannheim, Rechenzentrum, 2004.
Heinz KredelLast modified: Sun Jul 4 14:14:48 CEST 2004