SOAP Simple Object Access Protocol

Transcription

SOAP Simple Object Access Protocol
Adolphe Francois
Julien Marmel
Dominique Perlat
Olivier Printemps
SOAP
Simple Object Access Protocol
Encadrant : Chantal Taconet
Sommaire
Sommaire ....................................................................................................................... 2
Première Partie : Présentation Générale de SOAP...................................................... 3
1.
Présentation et fonctionnement SOAP........................................................... 3
2.
Présentation et fonctionnement des Webservices.......................................... 4
3.
Le protocole WSDL.......................................................................................... 4
4.
Le protocole UDDI ........................................................................................... 4
5.
Différence entre IIOP et SOAP....................................................................... 5
6.
Protocoles utilisés par SOAP........................................................................... 5
7.
Problèmes posés par SOAP :........................................................................... 8
a) Problèmes HTTP ............................................................................................ 8
b) Problèmes XML ............................................................................................. 8
c) Problèmes liés à SOAP .................................................................................. 9
8.
a)
b)
c)
d)
e)
Les fichiers WSDL ........................................................................................... 9
Services ........................................................................................................ 10
Port ............................................................................................................... 10
Message........................................................................................................ 11
Port Type et Opérations................................................................................ 12
Bindings ....................................................................................................... 13
Deuxième Partie : Installation et mise en œuvre ....................................................... 14
1.
a)
b)
Apache SOAP ................................................................................................. 14
Installation.................................................................................................... 14
Exemple d’utilisation ................................................................................... 15
a)
b)
NuSoap ............................................................................................................ 18
Installation.................................................................................................... 18
Exemples d’utilisation.................................................................................. 18
a)
b)
SOAP::Lite...................................................................................................... 20
Installation.................................................................................................... 20
Exemple d’utilisation : ................................................................................. 21
2.
3.
4.
Tests d’interoperabilité.................................................................................. 22
Troisième Partie : Exemples d’utilisation .................................................................. 23
1.
Exemple de Web Service : Google™ Web Service...................................... 23
2.
Exemple du gestionnaire d’imprimante....................................................... 24
a) Exemple 1 : l’imprimante HP....................................................................... 24
b) Exemple 2 : le gestionnaire d’impression .................................................... 33
c) Exemple 3 : le gestionnaire d’impression et WSDL ................................... 36
d) Exécution des exemples ............................................................................... 36
Bibliographie ............................................................................................................... 37
SOAP – Simple Access Protocol
2
Première Partie : Présentation Générale de SOAP
1. Présentation et fonctionnement SOAP
SOAP (Simple Object Access Protocol) est un protocole d’invocation de méthodes sur
des services distants. Basé sur XML, SOAP est un format de communication pour assurer
communication de machine à machine. Le protocole permet d’appeler une méthode RPC
(Remote Procedure Call) et d’envoyer des messages aux machines distantes via HTTP. Ce
protocole est très bien adapté à l’utilisation des services web car il permet de fournir au client
une grande quantité d’informations récupérées sur un réseau de serveurs tiers.
La version actuelle de SOAP est la 1.1. Cette version a été proposée au W3C en 2000
par UserLand, Ariba, Commerce One, Compaq, Developmentor, HP, IBM, IONA, Lotus,
Microsoft, SAP. Le W3C travaille actuellement sur la version 1.2 de SOAP, elle devrait sortir
fin 2002 et à pour but de supprimer l’utilisation des RPC au profit des messages.
SOAP permet donc l’échange d’information dans un environnement décentralisé et
distribué, comme Internet par exemple. Il permet l’invocation de méthodes, de services, de
composants et d’objets sur des serveurs distants et peut fonctionner sur de nombreux
protocoles (des systèmes de messagerie à l’utilisation de RPC). Cependant, il fonctionne
particulièrement bien avec le protocole HTTP, protocole très souvent utilisé avec SOAP.
SOAP utilise les protocoles HTTP et XML. HTTP comme mécanisme d’invocation de
méthodes en utilisant un des balises spécifiques pour indiquer la présence de SOAP comme
« <SOAP-ENV> ». Cela permet de franchir aisément les firewalls et proxy et facilite le
traitement en cas de filtrage. XML pour structurer les requêtes et les réponses, indiquer les
paramètres des méthodes, les valeurs de retours, et les éventuelles erreurs de traitements.
XML joue un rôle prépondérant dans SOAP, on peut distinguer plusieurs éléments :
• une enveloppe, expliquant comment la requête doit être traitée et présentant les
éléments contenus dans le message.
• un ensemble de règles de codage, permettant de différencier les types de données
transmises.
• une convention de représentation, permettant de représenter les appels aux procédures
de traitement et les réponses.
Même si SOAP ressemble beaucoup en termes de fonctionnalités à des protocoles
comme IIOP pour CORBA, ORPC pour DCOM, ou JRMP (Java Remote Method Protocol)
pour JAVA, il possède un avantage indéniable. En effets, SOAP utilise un mode texte alors
que les autres fonctionnent en mode binaire, cela facilite le passage des équipements de
sécurité.
SOAP – Simple Access Protocol
3
2. Présentation et fonctionnement des Webservices
Présentation :
Les Webservices permettent de faire communiquer deux sous-systèmes ensembles et
cela indépendamment des architectures utilisées. Ces systèmes vont pouvoir s’échanger des
services ou des traitements applicatifs. Les Webservices constituent un moyen de distribuer
un service de manière standard grâce à XML tout en respectant un modèle de développement
ayant déjà fait ses preuves comme CORBA ou DCOM (Microsoft). Un des avantages des
Webservices est de regrouper tous les acteurs derrière un seul et même standard.
Fonctionnement :
Pour expliquer le fonctionnement des webservices, il convient de distinguer plusieurs
étapes :
! Recherche dans un annuaire UDDI : le client cherche un service particulier, il
s’adresse à un annuaire qui va lui fournir la liste des prestataires habilités à satisfaire
sa demande. L’annuaire UDDI peut être comparé à un moteur de recherche sauf que
les documents sont remplacés par des services.
! Recherche de l’interface du composant à contacter : une fois la réponse reçue (en
XML) de l’annuaire, le client va chercher à communiquer via une interface. Cette
interface décrite en langage WSDL fournit l’ensemble des services disponibles. Elle
offre la possibilité de vérifier que le contrat correspond bien aux besoins demandés.
! Invocation du service : le client doit maintenant passer les paramètres attendus par le
service et assurer la communication avec le serveur. L’outil utilisé pour cela est le
Proxy, c’est l’objet qui permet la communication entre le client et le serveur. Il est
généré par le client en utilisant l’interface WSDL.
3. Le protocole WSDL
WSDL (Web Service Definition Langage) est un format de représentation des
interfaces de services Web en XML. Une analogie avec CORBA peut être faite, en effet
WSDL est la représentation XML du langage IDL (description d’interfaces).
WSDL a deux rôles prépondérants:
! Il sert de référence à la génération de Proxies.
! Il assure le couplage entre le client et le serveur par le biais des interfaces.
4. Le protocole UDDI
UDDI (Universal Description Discovery and Integration) est un protocole basé sur
XML qui sert à la publication et à l'exploration d'annuaires de Web Services. Il permet de
situer un service Web, de le décrire, et de l’intégrer. Ce protocole a été réalisé par IBM,
Microsoft et Ariba. Cependant UDDI est assez complexe et a été qualifié par certains
« d’usine à gaz ». C’est la raison pour laquelle IBM et Microsoft travaille actuellement sur un
autre protocole d’annuaire de services : Web Services Inspection (WS-Inspection). L’objectif
de WS-Inspection est de permettre à une entreprise de décrire facilement les services Web
dont elle dispose.
SOAP – Simple Access Protocol
4
5. Différence entre IIOP et SOAP
IIOP (Internet Inter-ORB Protocol) est un protocole de transfert de méthode utilisé par
CORBA. Il définit le format des messages échangés entre la machine cliente et la machine
serveur. IIOP va permettre d’envoyer et de recevoir des types complexes de données. Les
clients et serveurs peuvent employer n’importe quel mélange de langages et de plateformes.
IIOP est un protocole très complet qui est capable d’effectuer tous les transferts exigés par
SOAP. Cependant l’utilisation de SOAP peut être parfois préférable pour plusieurs raisons.
Tout d’abord, l’utilisation de IIOP nécessite de compiler et distribuer des souches
clients pour chaque type de clients avec qui l’on communique. Ce n’est évidemment pas très
pratique, en particulier quand le nombre de plateformes différentes ou de langages différents
est important.
Dans le cas des services web, IIOP va poser des problèmes pour le franchissement des
équipements de filtrage (firewall, proxy). Cela va demander un travail en plus de la part de
chaque personne administrant l’équipement. Au contraire, l’utilisation de SOAP ne pose
absolument pas de problèmes au niveau des firewalls. SOAP étant un protocole utilisant
HTTP, il y a peu de chance qu’il soit bloqué lors d’un filtrage. Evidemment CORBA, au
travers de IIOP, est plus performant : il y a moins de données transitant sur le réseau, et les
opérations de conversion / déconversion sont traitées plus rapidement. Cependant avec SOAP
les données circulent en format texte et en clair sur le réseau. Leur lecture en est donc facilitée
et le déboguage est beaucoup plus simple.
SOAP est donc un très bon protocole si l’on cherche à dialoguer avec des plateformes
hétérogènes, ce qui est particulièrement le cas dans toutes les applications de type « Web
Services ». En fait, l’utilisation de CORBA ou de SOAP va surtout dépendre de ce que l’on
doit faire : dans le cas des webservices SOAP semble être une bonne solution, par contre si
l’on souhaite faire des applications distribuées classiques comme du calcul distribué, on
choisira plutôt CORBA.
6. Protocoles utilisés par SOAP
SOAP se sert le plus souvent de deux protocoles : HTTP et XML.
Un message SOAP est écrit en XML. HTTP est utilisé comme protocole de transport.
Les messages SOAP vont donc être encapsulés dans HTTP, ce qui permet une
utilisation et une compatibilité très importante avec les réseaux et équipements existants.
HTTP est le protocole de transport le plus utilisé mais il n’est pas impossible de trouver des
implémentations de SOAP sur d’autres protocoles (avec SMTP par exemple).
Un message SOAP est un document XML qui possède une enveloppe SOAP et
éventuellement une déclaration XML. L’enveloppe SOAP est composée d’un corps SOAP et
éventuellement d’un en-tête.
•
•
•
•
Les règles de syntaxe sont les suivantes :
Un message SOAP MUST être codé en XML
Un message SOAP MUST avoir une enveloppe SOAP
Un message SOAP CAN avoir un entête SOAP (header)
Un message SOAP MUST avoir un corps SOAP (body)
SOAP – Simple Access Protocol
5
•
•
•
•
Un message SOAP MUST utiliser l’espace de désignation de l’enveloppe SOAP
Un message SOAP MUST utiliser l’espace de désignation d’encodage SOAP
Un message SOAP MUST NOT contenir une référence à une DTD
Un message SOAP MUST NOT contenir des instructions de type XML Processing
Un message SOAP va être constitué d’une enveloppe et d’un corps. C’est à l’intérieur
du corps (body) que l’on trouve le contenu :
//enveloppe du message
<soap:Envelope
//espace de nommage pour l’enveloppe SOAP
xmlns:SOAP="http://schemas.xmlsoap.org/soap/envelope/"
//on définit le type d’encodage du message
SOAP:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
//espace de nommage pour les types de variables
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
//espace de nommage pour l’appel de méthodes
xmlns:tns="http://soapinterop.org/">
//corps
<soap:Body>
//espace de nommage pour la fonction getStateName
<m:getStateName xmlns:m="http://soapware.org/">
//on spécifie un argument à passer à getStatName
<statenum xsi:type="xsd:int">41</statenum>
</m:getStateName>
//gestion d’erreurs
<soap:fault>
</soap:fault>
</soap:Body>
</soap:Envelope>
<envelope> est la racine ; <header>, <body>,et <fault> sont les enfants.
SOAP – Simple Access Protocol
6
Structure d’un message SOAP
Exemple: Message SOAP encapsulé dans une requête HTTP
Voici une requête SOAP typique (avec les en-têtes HTTP) pour un appel à une
méthode RPC nommée EchoString, qui prend une chaîne comme paramètre :
POST /test/simple.asmx HTTP/1.1
Host: 131.107.72.13
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction: "http://soapinterop.org/echoString"
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:tns="http://soapinterop.org/"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<tns:echoString>
<inputString>string</inputString>
</tns:echoString>
</soap:Body>
</soap:Envelope>
Le nom de la méthode est appelé par la balise <tns:echoString> et le paramètre de
type chaîne est défini par <inputString>. La méthode qui est invoqué est donc de cette
forme :
SOAP – Simple Access Protocol
7
public String echoString(String inputString);
Le serveur réponds alors:
HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Content-Length: length
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:tns="http://soapinterop.org/"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<tns:echoStringResponse>
<Return>string</Return>
</tns:echoStringResponse>
</soap:Body>
</soap:Envelope>
Les règles de sérialisation du type de données de chaîne, ainsi que la forme de l'appel à
une méthode, sont définies dans SOAP 1.1, sections 5 et 7 (http://www.w3.org/tr/soap).
7. Problèmes posés par SOAP :
Ces problèmes concernent principalement l’interopérabilité des messages SOAP de
type RPC. La plupart des problèmes posés par SOAP ne concernent pas directement le
protocole lui-même mais plutôt les protocoles utilisés, comme XML ou HTTP. Ils peuvent
être divisés en trois catégories :
- problèmes http
- problèmes XML
- problèmes liés au protocole SOAP
a) Problèmes HTTP
HTTP est utilisé pour le transport des messages SOAP en XML. Or certaines balises
spécifiques à SOAP ne vont pas être bien interprétées par tous les clients HTTP. Cela va
dépendre du client et ne pas fonctionner dans certains cas. On peut prendre l’exemple de la
fonction SOAPAction : la valeur de SOAPAction doit être en guillemets sauf s’il s’agit d’une
valeur nulle.
Exemple : « SOAPAction: http://test.org/ » ou « SOAPAction: »
Cependant certains clients ne sont pas capables de fournir une valeur d’entête HTTP
nulle, si le serveur en attends une, l’appel ne fonctionnera pas.
b) Problèmes XML
Les problèmes d’interopérabilité XML concernent l’analyse du langage XML. SOAP
repose sur l’utilisation de ce langage, donc si XML pose des problèmes d’implémentations,
ceux-ci vont poser des problèmes sur SOAP.
SOAP – Simple Access Protocol
8
c) Problèmes liés à SOAP
En lui-même, SOAP est relativement simple ; il requiert que les messages soient
placés dans une enveloppe avec le texte du message inclus dans un élément du corps.
Cependant il existe un certain nombre de problèmes d’interopérabilité comme par
exemple le problème lié à l’implémentation de l’attribut « mustUnderstand ». Les
spécifications de SOAP indiquent que si cet attribut est défini sur la valeur « 1 », il devra être
traité. Pourtant certaines implémentations de SOAP ne le font pas (principalement les
premières à avoir été développées). De nombreux autres problèmes d’interopérabilité ont été
découverts, ils sont consultables sur le forum http://groups.yahoo.com/group/soapbuilders.
Cette liste contribue grandement à l’amélioration du protocole.
8. Les fichiers WSDL
Afin des décrire les services disponibles sur un serveur, un langage de description de
service a été mis en place : le WSDL (Web Service Description Langage). Ce langage est basé
sur XML. Les fichiers WSDL contiennent donc la description de l’accès à des Web services
ainsi que des messages qui seront échangés avec les services en question. (Arguments, types
de donnée…). Une fois muni de cette description, appelée aussi parfois « contrat », le client
va pouvoir dialoguer avec les services de manière adéquate. On peut par exemple générer
automatiquement à partir du fichier WSDL un client ou un proxy pour ce service.
Pour comprendre les différentes zones d’un descripteur WSDL, le schéma suivant où
se situent les différents éléments décrits dans un fichier WSDL.
Différents éléments d’un fichier WSDL (source : LearnXmlws,
http://www.learnxmlws.com/tutors/wsdl/wsdl.aspx)
SOAP – Simple Access Protocol
9
Un fichier WSDL commence par <definition> et finit par </definition>. C’est à
l’intérieur de cette espace que l’on va déclarer tous les éléments constituant la description.
Nous allons prendre l’exemple du Web Service de Google pour montrer comment se construit
un fichier WSDL.
Début de la description des services avec
déclaration des différents schémas utilisés
Nom unique identifiant cet ensemble
de service au niveau du serveur
<definitions name="urn:GoogleSearch"
targetNamespace="urn:GoogleSearch"
xmlns:typens="urn:GoogleSearch"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns="http://schemas.xmlsoap.org/wsdl/">
...
</definition>
a) Services
Un service est la mise à disposition d’une ou plusieurs méthodes. On peut imaginer
par exemple une classe avec plusieurs méthodes invocables à distance. La classe sera le
service, et chaque méthode sera une opération sur ce service.
La définition d’un service se fait par l’utilisation de <service></service>.
b) Port
Pour chaque service on va définir des ports par lesquels ce service sera disponible. En
effet, il est possible de rendre disponible un service sur plusieurs supports différents : HTTP
GET, SOAP, SMTP…
Définition d’un
service
Définition d’un port avec l’adresse du
service (ici une URL)
<service name="GoogleSearchService">
<port name="GoogleSearchPort" binding="typens:GoogleSearchBinding">
<soap:address location="http://api.google.com/search/beta2"/>
</port>
</service>
SOAP – Simple Access Protocol
10
c) Message
Les messages sont les éléments échangés entre le client et le serveur lors d’une
opération sur le port d’un service. Ces messages sont constitués de plusieurs parties (part) qui
représentent chacune une donnée avec un type associé.
<message name="doGoogleSearch">
<part name="key"
<part name="q"
<part name="start"
<part name="maxResults"
<part name="filter"
<part name="restrict"
<part name="safeSearch"
<part name="lr"
<part name="ie"
<part name="oe"
</message>
type="xsd:string"/>
type="xsd:string"/>
type="xsd:int"/>
type="xsd:int"/>
type="xsd:boolean"/>
type="xsd:string"/>
type="xsd:boolean"/>
type="xsd:string"/>
type="xsd:string"/>
type="xsd:string"/>
Définition d’un
message
Chaque « part » du
message a un nom et
un type. Ici un type
simple
Utilisation d’un type
complexe
<message name="doGoogleSearchResponse">
<part name="return"
type="typens:GoogleSearchResult"/>
</message>
Ainsi, il est possible définir ses propres types en se basant sur les types de base. En
lisant cette définition dans le fichier WSDL, le client pourra générer éventuellement
automatiquement une structure ou une classe reflétant cette description.
Voici un exemple de type complexe qui représente le résultat d’une recherche sur le
Web service de Google™ :
Définition d’un type complexe
Lien vers un autre type complexe
<type>
<xsd:complexType name="ResultElement">
<xsd:all>
<xsd:element name="summary" type="xsd:string"/>
<xsd:element name="URL" type="xsd:string"/>
<xsd:element name="snippet" type="xsd:string"/>
<xsd:element name="title" type="xsd:string"/>
<xsd:element name="cachedSize" type="xsd:string"/>
<xsd:element name="relatedInformationPresent" type="xsd:boolean"/>
<xsd:element name="hostName" type="xsd:string"/>
<xsd:element name="directoryCategory" type="typens:DirectoryCategory"/>
<xsd:element name="directoryTitle" type="xsd:string"/>
</xsd:all>
</xsd:complexType>
</type>
SOAP – Simple Access Protocol
11
d) Port Type et Opérations
Une méthode peut être représentée par une opération qui prend un message en entrée
et renvoie un message en sortie. Ainsi chaque opération représentée par
<operation></operation> indique les flux de messages en entrée et en sortie
correspondants en définissant les élément <input/> et <output/>.
Enfin, la collection de toutes les opérations d’un service est rassemblée dans un port
type.
Définition d’une opération
(méthode)
<portType name="GoogleSearchPort">
<operation name="doGetCachedPage">
<input message="typens:doGetCachedPage"/>
<output message="typens:doGetCachedPageResponse"/>
</operation>
<operation name="doSpellingSuggestion">
<input message="typens:doSpellingSuggestion"/>
<output message="typens:doSpellingSuggestionResponse"/>
</operation>
On indique le nom
des messages en
entrée et en sortie
<operation name="doGoogleSearch">
<input message="typens:doGoogleSearch"/>
<output message="typens:doGoogleSearchResponse"/>
</operation>
</portType>
SOAP – Simple Access Protocol
12
e) Bindings
Enfin, pour compléter la description, il faut relier certains éléments entre eux. C’est le
rôle des bindings représentés par les balises <binding></binding>. On va spécifier
notamment tout ce qui concerne l’encodage des données dans les messages en indiquant les
règles que l’on utilise.
Définition de la couche
transport utilisée
Pour chaque opération, on défini les règles
d’encodage des données
<binding name="GoogleSearchBinding" type="typens:GoogleSearchPort">
<soap:binding style="rpc"
transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="doGoogleSearch">
<soap:operation soapAction="urn:GoogleSearchAction"/>
<input>
<soap:body use="encoded"
namespace="urn:GoogleSearch"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
</input>
<output>
<soap:body use="encoded"
namespace="urn:GoogleSearch"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
</output>
</operation>
</binding>
SOAP – Simple Access Protocol
13
Deuxième Partie : Installation et mise en œuvre
Un des avantages de SOAP est sa capacité à faire communiquer des plateformes
hétérogènes. C’est pourquoi plusieurs implémentations de SOAP on été développées (ou sont
encore en développement). Nous en avons testé quelques unes, utilisant chacune un langage
différent : Apache SOAP pour une implémentation Java, NuPHP pour le PHP, et SOAP::Lite
pour le langage Perl. Pour chacune, nous allons présenter brièvement les procédures
d’installation, et quelques exemples de mise en œuvre.
1. Apache SOAP
La distribution Apache SOAP (http://xml.apache.org/soap/) fournit les librairies
nécessaires pour invoquer des services SOAP distants, et des outils côté serveur pour
implémenter des services SOAP. En tant que librairie cliente, il offre une API pour invoquer
des services SOAP RPC et une API pour envoyer et recevoir des messages SOAP. Pour
mettre en œuvre un service accessible par RPC ou par messages, Apache SOAP doit être
hébergé par un conteneur de servlets comme Apache Tomcat. Le transport principal est le
http, même si le support d’autres protocoles peut être ajouté (SMTP par exemple).
a) Installation
Prérequis côté serveur : jdk (1.2 ou ulterieur), un conteneur de servlets (tomcat par
exemple), un parseur XML (xerces par exemple), les classes soap (le fichier soap.war inclus
dans la distribution de soap suffit pour tomcat), classes annexes dans certains cas.
Prérequis côté client : classes soap, mail.jar, activation.jar, classpath correct pour
compiler le code java.
Tomcat est un conteneur de servlets JSP qui intègre son propre serveur web. Il ne
necessite donc pas l’installation d’un serveur web séparé. L’installation de tomcat ne pose pas
de problème particulier. Il suffit d’extraire l’archive fournie et de démarrer le serveur pour
vérifier que les exemples de servlets fonctionnent. Le serveur se lance par défaut sur le port
8080, qui peut être modifié dans les fichiers de configuration de tomcat.
L’installation de soap sous tomcat se fait simplement en copiant l’archive web
soap.war dans le repertoire d’applications web de tomcat (jakarta-tomcat-4.0.3/webapps). On
peut également créer un nouveau <Context> pour le serveur tomcat, qui indiquera où trouver
les classes SOAP. Cela implique d’ajouter les chemins d’accès vers tous les services à
deployer dans le classpath. Dans les deux cas, il faut systématiquement redémarrer le serveur
pour prendre en compte les modifications.
Nous avons choisi de mettre en œuvre Apache SOAP de la première façon, qui utilise
la configuration par défaut du serveur tomcat.
Lancement et arret du serveur :
/mci/projet/proj01/SOAP/jakarta-tomcat-4.0.3/bin/startup.sh
/mci/projet/proj01/SOAP/jakarta-tomcat-4.0.3/bin/shutdown.sh
SOAP – Simple Access Protocol
14
Pour tester le bon fonctionnement du serveur, il suffit d’ouvrir les pages suivantes :
http://elaphe.int-evry.fr:8080/soap/servlet/rpcrouter
http://elaphe.int-evry.fr:8080/soap/servlet/messagerouter
Le serveur doit répondre
« SOAP (RPC|Message) Router
Sorry, I don't speak via HTTP GET- you have to use HTTP POST to talk to
me. »
Si le client est correctement configuré, la commande suivante affichera la liste des
services déployés sur le serveur :
java org.apache.soap.server.ServiceManagerClient http://elaphe.intevry.fr:8080/soap/servlet/rpcrouter list
b) Exemple d’utilisation
Notre exemple conmprend 3 fichiers :
EchoService.java – Le code du serveur d’echo
GetEcho.java – le code du client chargé d’appeler le service d’echo
DeploymentDescriptor.xml contient la description du service. Ce fichier
facilite le déploiement d’un service sur le serveur.
Compiler les sources java (javac *.java) apres avoir verifie le classpath.
Placer les classes dans "/mci/projet/proj01/SOAP/jakarta-tomcat4.0.3/webapps/soap/WEB-INF/classes/samples/echo"
! serveur : EchoService.java
package samples.echo;
public class EchoService {
public String getEcho(String s){
return "*echo* " + s;
}
Renvoi de la chaine reçue
}
SOAP – Simple Access Protocol
15
! client : GetEcho.java
package samples.echo;
import
import
import
import
Importation des classes
nécessaires
java.net.*;
java.util.*;
org.apache.soap.*;
org.apache.soap.rpc.*;
public class GetEcho {
public static void main (String[] args) throws Exception {
if (args.length != 2
&& (args.length != 3 || !args[0].startsWith ("-"))) {
System.err.println ("Usage: java " + GetEcho.class.getName () +
" [-encodingStyleURI] SOAP-router-URL chaine");
System.exit (1);
}
// Traitement des arguments.
int offset = 3 - args.length;
String encodingStyleURI = args.length == 3
? args[0].substring(1)
: Constants.NS_URI_SOAP_ENC;
URL url = new URL (args[1 - offset]);
String chaine = args[2 - offset];
Traitement des
arguments
// Construction de l’appel.
Call call = new Call ();
Construction de l’appel
call.setTargetObjectURI ("urn:test-myEcho");
call.setMethodName ("getEcho");
call.setEncodingStyleURI(encodingStyleURI);
Vector params = new Vector ();
params.addElement (new Parameter("chaine", String.class, chaine, null));
call.setParams (params);
// appel: l’URI action est vide (non utilisée par XML-SOAP)
Response resp = call.invoke (/* router URL */ url, /* actionURI */ "" );
// Check the response.
if (resp.generatedFault ()) {
Fault fault = resp.getFault ();
Appel
System.err.println("Generated fault: " + fault);
} else {
Parameter result = resp.getReturnValue ();
System.out.println (result.getValue ());
}
Verification de la
réponse
}
}
Affichage du résultat
SOAP – Simple Access Protocol
16
! DeploymentDescriptor.xml
<isd:service xmlns:isd="http://xml.apache.org/xml-soap/deployment"
id="urn:test-myEcho">
<isd:provider type="java"
scope="Application"
methods="getEcho">
<isd:java class="samples.echo.EchoService"/>
</isd:provider>
<isd:faultListener>org.apache.soap.server.DOMFaultListener</isd:faultListener>
</isd:service>
! Utilisation :
Les services peuvent être déployés à l’aide de l’interface web de la distibution Apache
SOAP (http://elaphe.int-evry.fr:8080/soap), ou plus simplement en utilisant la classe
ServiceManagerClient fournie :
java org.apache.soap.server.ServiceManagerClient
http://localhost:8080/soap/servlet/rpcrouter deploy
DeploymentDescriptor.xml
java org.apache.soap.server.ServiceManagerClient
http://localhost:8080/soap/servlet/rpcrouter undeploy urn:test-myEcho
java org.apache.soap.server.ServiceManagerClient
http://localhost:8080/soap/servlet/rpcrouter list
Le client prend en paramètres l’adresse du routeur RPC et le texte à envoyer :
java samples.echo.GetEcho http://elaphe.intevry.fr:8080/soap/servlet/rpcrouter montexte
Apache SOAP n’offre pas de support du wsdl côté client. Un utilitaire séparé fourni
par IBM permet toutefois de créer un code client à partir d’un fichier wsdl, mais son
utilisation n’est pas pratique.
SOAP – Simple Access Protocol
17
2. NuSoap
NuSOAP est une implémentation en PHP de SOAP disponible gratuitement sur
Internet (licence LGPL) : http://dietrich.ganx4.com/nusoap/. Il a été développé par Dietrich
Ayala pour Nusphere (IDE pour PHP : http://www.nusphere.com/). Ce kit est constitué de
plusieurs classes permettant la mise en place de clients et de serveurs SOAP en utilisant le
langage PHP. Ce langage est très utilisé pour construire des sites Web dynamiques, l’accès
aux Web Services est donc la bienvenue.
a) Installation
Cette implémentation de SOAP est assez simple à installer et à utiliser puisqu’aucun
serveur spécifique (autre qu’un simple serveur Web) n’est requis. Il suffit de mettre sur le
serveur un simple script PHP pour avoir acces à des services. La partie serveur est démarrée à
chaque appel de l’URL du script implémentant la partie serveur pour SOAP. C’est entre autre
cela qui fait la simplicité de mise en place de cette implémentation : il suffit de faire un
« include » du fichier contenant les classe de NuSOAP pour pouvoir déployer ou invoquer des
services.
b) Exemples d’utilisation
! Script serveur : déploiement du service ’myEcho’
<?php
require_once('../nusoap/nusoap.php');
$s = new soap_server;
$s->register('myEcho',false,false,"urn:myEcho");
function myEcho($chaine){
// optionally catch an error and return a fault
if($chaine == ''){
return new soap_fault('Client','','La chaine est vide.');
}
$res="vous avez envoyé:".$chaine;
return $res;
}
$s->service($HTTP_RAW_POST_DATA);
?>
SOAP – Simple Access Protocol
Inclusion des classes NuSoap
Création d’un objet
« serveur »
Enregistrement du service
‘myEcho’ auprès du serveur
Fonction effectuant le service
(Fonction qui sera appelée
par RPC)
Envoie des réponses du
serveur au client : Ici,
NuSoap va générer le
message réponse du serveur
en XML et l’envoyer dans la
réponse http au client.
18
! Script Client : appel direct au service ‘myEcho’ (sans utiliser le fichier WSDL)
Appel aux classes de
NuSOAP
Préparation du tableau
contenants les paramètres à
passer au service
$lachaine : variable
contenant la chaine à
passer lors de l’appel
Création de l’objet client
avec l’URL du service
SOAP à appeler. Ici c’est
l’URL du script serveur
écrit en PHP
<?php
require_once('../nusoap/nusoap.php');
if($lachaine!=NULL){
$parameters = array('chaine1'=>$lachaine);
$soapclient = new
soapclient('http://www.minet.net/~ospring/testsoap/rpcrouter.php');
echo $soapclient->call('myEcho',$parameters);
}
else
echo "<- Remplir le formulaire";
?>
Appel de la méthode
distante ‘myEcho’
avec passage du
tableau des
paramètres
! Script Client : appel direct service ‘myEcho’ avec le fichier WSDL et le proxy
NuSOAP permet, si l’on utilise les descripteurs de services écrits en WSDL, de
générer un proxy pour service. Ce proxy permet d’accéder à la méthode distante comme si
elle était une méthode d’un objet local. Cela permet d’avoir un code beaucoup plus clair et
moins lourd.
SOAP – Simple Access Protocol
19
Exemple d’utilisation :
<?php
require_once('../nusoap/nusoap.php');
$soapclient= new
soapclient('http://www.minet.net/~ospring/testsoap/myEcho.wsdl','wsdl'
);
$proxy=$soapclient->getProxy();
$res=$proxy->myEcho($lachaine);
echo $res;
Appel à la procédure
distante via le proxy
Création du proxy
Création du client à
partir d’un fichier
WSDL
3. SOAP::Lite
SOAP::Lite (http://www.soaplite.com) est un ensemble de modules Perl qui
fournissent une interface simple et légère vers SOAP, côté client et côté serveur. Il est
préférable d’installer la distribution en tant que root bien qu’il soit possible d’installer les
modules dans son propre repertoire de travail.
a) Installation
De nombreux modules sont nécessaires à SOAP::Lite
MIME-Base64-2.12
IO-1.20
URI-1.19
MIME-Lite-2.117
HTML-Parser-3.26
HTML-Tagset-3.03
libnet-1.12
MIME-tools-5.411
IO-stringy-2.108
MailTools-1.46
XML-Parser-2.31
libwww-perl-5.65
…
Les commandes pour installer les modules dans ~/perl (pour un utilisateur
normal) sont :
perl Makefile.PL LIB=~/perl
make
make test
make install
SOAP – Simple Access Protocol
20
Il faut parfois éditer le fichier Makefile.PL pour indiquer le chemin d’accès des
modules déjà ajoutés (ce qui revient à modifier la variable @INC). Ajouter en tête du fichier
(par exemple) :
use lib '/mci/projet/proj01/perl';
use lib '/mci/projet/proj01/perl/i386-linux';
Une fois que tous les modules sont présents, extraire la distribution SOAP::Lite et
modifier le fichier Makefile.PL (ajouter use lib '/mci/projet/proj01/perl/i386-linux'; use lib
'/mci/projet/proj01/perl'; en tête du fichier).
Comme pour les autres modules, lancer les commandes :
perl Makefile.PL LIB=~/perl
make
make test
make install
b) Exemple d’utilisation :
! clientEcho.pl (acces par descripteur wsdl)
#!perl -w
use lib '/mci/projet/proj01/perl';
use SOAP::Lite;
Emplacement des modules Perl
nécessaires
my $lachaine = shift || die "usage: clientEcho <string>\n";
# on appelle le service Java par sa description wsdl
my $soapclient = SOAP::Lite->service("http://elaphe.intevry.fr:8080/soap/wsdl/test-myEcho.wsdl");
my $result = $soapclient->getEcho($lachaine);
print "resultat (Java avec wsdl): $result\n";
Récuperation du paramètre en
entrée
Appel du service Apache par sa
description wsdl
# on appelle le service Java par le serveur rpc
my $soapclient2 = SOAP::Lite->uri('urn:test-myEcho')
->proxy('http://elaphe.int-evry.fr:8080/soap/servlet/rpcrouter');
my $result2 = $soapclient2->getEcho($lachaine)->result;
Appel du service Apache
print "resultat (Java par RPC) : $result2\n";
par le serveur RPC
# on appelle le service PHP par sa description wsdl
my $soapclient3 = SOAP::Lite
->service("http://elaphe.int-evry.fr:8080/soap/wsdl/myEcho.wsdl");
my $result3 = $soapclient3->myEcho($lachaine);
print "resultat (PHP avec wsdl): $result3\n";
Appel du service NuSOAP par sa
description wsdl
# on appelle le service PHP par le serveur rpc
my $soapclient4 = SOAP::Lite->uri('urn:myEcho')
->proxy('http://www.minet.net/~ospring/testsoap/rpcrouter.php');
my $result4 = $soapclient4->myEcho($lachaine)->result;
print "resultat (PHP par RPC) : $result4\n";
Appel du service NuSOAP par
le serveur RPC
SOAP – Simple Access Protocol
21
! Utilisation
La commande pour lancer le client echo est
perl clientEcho.pl montexte
L’implémentation côté serveur peut se faire par cgi ou à l’aide d’un serveur web
possédant un module perl. Nous ne sommes pas parvenus à mettre en œuvre la solution cgi,
ceci étant rendu difficile par l’absence de processus de débuggage lors d’une erreur sur le
serveur (« Erreur 500 »).
4. Tests d’interoperabilité
L’objectif principal de SOAP est de permettre à des applications de faire appel à des
méthodes distantes quelles que soient les plates-formes utilisées de part et d’autre. Nous
avons naturellement voulu vérifier cela sur la mise en œuvre simple du service Echo.
Les services Echo ont été déployés en Java (avec Apache SOAP) en PHP (avec
NuSOAP). Nous avons tesé des clients Java, PHP, et Perl.
Le client en Java accède sans difficulté au service sous Java. L’appel au routeur RPC
en PHP par le client Java nous a tout d’abord posé problème : celui-ci nous renvoyait une
erreur dont nous ne comprenions pas le sens. Nous nous sommes finalement rendus compte
que le problème venait de la présence d’un accent dans la chaîne retournée. Après suppression
de l’accent, l’appel fonctionnait parfaitement.
Le client PHP et le client Perl fonctionnent sur les deux serveurs sans problème.
Ces tests ne sont qu’un aperçu des possibilités offertes par SOAP et des problèmes
d’interopérabilité qu’il peut poser. Les modes d’encodage et l’utilisation de types complexes
notamment semblent poser des difficultés lors de la mise en place de plates-formes
hétérogènes.
SOAP – Simple Access Protocol
22
Troisième Partie : Exemples d’utilisation
1. Exemple de Web Service : Google™ Web Service
Afin, de mieux comprendre les rôles que peuvent remplir les Web Services ainsi que
leur fonctionnement, nous en avons testé un existant et développé des clients permettant de
l’exploiter. Google™ est un moteur de recherche sur le Web très connu offrant des options de
recherches assez avancées. Google™ met à disposition un Web service permettant
d’interroger le moteur de recherche via SOAP. Un fichier WSDL est donné pour ce fait et
donne l’accès à trois méthodes :
• doGetCachedPage : cette méthode permet de récupérer les page Web en cache dans le
moteur de recherche.
• doGoogleSearch : Cette méthode permet de lancer une recherche sur le moteur et
d’en récupérer 10 résultats (maximum).
• doSpellingSuggestion : permet de traduire du texte
Le client a été développé en PHP. Il permet de lancer une recherche en spécifiant le
nombre de résultat, puis, pour chaque résultat, il permet de récupérer la page correspondante
en cache dans le moteur.
Appel du Web Service de
recherche sur Google™
Utilisation des résultats. La structure complexe du
résultat a été placée dans des tableaux imbriqués
<?php
require_once('../nusoap/nusoap.php');
if(isset($query)){
$soapclient = new
soapclient('http://www.minet.net/~ospring/testsoap/GoogleSearch.wsdl','wsdl');
$proxy=$soapclient->getProxy();
$res=$proxy>doGoogleSearch("X4YaHThwrxRUii7siFP0fxXFz9XgoJrT",$query,$start_index,$numres,tru
e,"",false,"","","");
?>
Nombre de réponses trouvées:&nbsp; <?php echo $res['estimatedTotalResultsCount'];
?><br>
Temps de recherche:&nbsp; <?php echo $res['searchTime']; ?><br>
<?php for($i=0;$i< count($res['resultElements']) &&
$res['estimatedTotalResultsCount']>0;$i++){ ?>
</td></tr>
<tr>
<td><?php $index=$i+$start_index;echo $index; ?></td>
<td>
<b><?php echo $res['resultElements'][$i]['title']; ?></b><br>
<a href='<?php echo $res['resultElements'][$i]['URL'];?>'><?php echo
$res['resultElements'][$i]['URL']; ?></a><br>
<a href="clientCacheGoogle.php?cached_url=<?php echo
htmlspecialchars($res['resultElements'][$i]['URL']);?>">cached page</a>
<?php } ?>
SOAP – Simple Access Protocol
23
2. Exemple du gestionnaire d’imprimante
Nous avons essayé dans cette partie d’implémenter l’exemple du gestionnaire
d’imprimante en java avec SOAP et de voir ainsi les différences avec CORBA. Pour faciliter
la compréhension nous avons effectué trois versions du gestionnaire d’imprimante.
a) Exemple 1 : l’imprimante HP
Dans cet exemple le service représente une imprimante seule et sur laquelle on peut
demander une impression et obtenir des informations sur les taches en cours.
Imprime
SOAP (http)
ImprimanteHP.class
GetInfos
Service
Clients
Figure 1
Nous allons donc voir dans un premier comment créer le service puis nous verrons
comment écrire les clients.
i)
Création du service SOAP
L’écriture d’un service SOAP basé sur les RPC est très simple et se fait en trois
étapes :
! Créer la classe Java contenant le service SOAP à publier
! Créer un « deployment descriptor » décrivant le service
! Publier le service
! Création du service
Un service SOAP peut être juste n’importe quelle classe Java habituelle qui expose
des méthodes publiques. L’écriture de cette classe n’est en rien spécifique à SOAP. La seule
restriction est que les paramètres des méthodes doivent être serialisables . Les types par
défaut supportés par SOAP sont les suivants :
Notre service a donc la forme suivante :
o Tous les types primitifs et les “wrapper” correspondants
o Java arrays
o java.lang.String
o java.util.Date
o java.util.GregorianCalendar
o java.util.Vector
SOAP – Simple Access Protocol
24
o
o
o
o
o
o
o
o
o
o
java.util.Hashtable
java.util.Map
java.math.BigDecimal
javax.mail.internet.MimeBodyPart
java.io.InputStream
javax.activation.DataSource
javax.activation.DataHandler
org.apache.soap.util.xml.QName
org.apache.soap.rpc.Parameter
java.lang.Object (en tant que JavaBean)
SOAP – Simple Access Protocol
25
package GIsoap.exemple1;
import java.net.*;
import java.io.*;
public class ImprimanteHP
{
private short tacheCourante;
private String nom;
ImpInfos inf;
public ImprimanteHP() {
nom=new String("hp");
System.out.println("Instantiation de l'imprimante :
"+ nom);
}
public ImpInfos getInfo()
{
InetAddress maMachine;
String
machine;
try {
maMachine = InetAddress.getLocalHost();
machine = maMachine.getHostName();
} catch (UnknownHostException u) {
machine = new String("machine inconnue");
}
inf = new ImpInfos(nom,"", machine, tacheCourante) ;
return inf;
}
public TacheInfos envoiDocument (String n)
throws TacheRefusee {
int t;
// ouverture du fichier
// recupere taille du fichier
File f=new File(n);
if ( ! f.isFile() ) { throw new TacheRefusee(nom,n+" : n'est pas un
fichier");}
t = (int)f.length();
if (tacheCourante > 2) {
System.out.println("Je suis définitivement surchargée, il faut me
redémarre
r !");
throw new TacheRefusee(nom,"surcharge");
}
System.out.println("Impression du document : "+ n + " sur " + nom + "
taille "
+ t);
tacheCourante++;
return (new TacheInfos(tacheCourante, t));
}
}
SOAP – Simple Access Protocol
26
On remarque que les méthodes getInfos et envoiDocument renvoie chacun un objet
que nous avons défini. Ces objets seront transmis aux clients en réponse aux appels des
méthodes. Comme nous l’avons vu plus précédemment les objets doivent être sérialisables.
Nous avons donc deux possibilités soit nous écrivons nos propres sérialiseurs soit nous
utilisons la classe BeanSerializer de JavaBean fourni avec Apache SOAP. La deuxième
possibilité est en fait la plus simple. Pour cela nous devons chaque classe un constructeur par
défaut et rajouter les méthodes setXXX et getXXX pour chaque donnée de la classe.
package GIsoap.exemple1;
public class TacheInfos
{
private short tacheCourante;
private int
tailleFichier;
public TacheInfos()
{}
public TacheInfos( short tacheCourante, int tailleFichier)
{
this.tacheCourante = tacheCourante;
this.tailleFichier = tailleFichier;
}
public void setTacheCourante(short tacheCourante)
{
this.tacheCourante = tacheCourante;
}
public short getTacheCourante()
{
return tacheCourante;
}
public void setTailleFichier(int tailleFichier)
{
this.tailleFichier = tailleFichier;
}
public int getTailleFichier()
{
return tailleFichier;
}
}
TacheInfos.java
SOAP – Simple Access Protocol
27
public class ImpInfos
{
private String imprimante;
private String serveur;
private String machine;
private short tacheEnCours;
public ImpInfos()
{
tacheEnCours= 2;
}
public ImpInfos( String imprimante, String serveur, String machine, short
tacheEnCou
rs)
{
this.imprimante = new String(imprimante);
this.serveur = new String(serveur);
this.machine = new String(machine);
this.tacheEnCours = tacheEnCours;
}
public void setImprimante(String imprimante)
{
this.imprimante = imprimante;
}
public String getImprimante()
{
return imprimante;
}
public void setServeur(String serveur)
{
this.serveur = serveur;
}
public String getServeur()
{
return serveur;
}
public void setMachine(String machine)
{
this.machine = machine;
}
public String getMachine()
{
return machine;
}
public void setTacheEnCours(short tacheEnCours)
{
this.tacheEnCours = tacheEnCours;
}
public short getTacheEnCours()
{
return tacheEnCours;
}
public String toString()
{
return imprimante + " "+ serveur + " "+ machine + tacheEnCours;
}
}
ImpInfos.java
SOAP – Simple Access Protocol
28
Voilà c’est fini en ce qui concerne la création du service.
! Création du « deployment descriptor »
Pour déployer un service on peut soit utiliser l’interface de déploiement fourni le
serveur Apache en utilisant le navigateur soit utiliser les commandes de gestion de services
pour lequel il faut un fichier XML décrivant le service.
Voici ce fichier pour notre exemple :
<isd:service xmlns:isd="http://xml.apache.org/xml-soap/deployment"
id="urn:ImprimanteHP">
<isd:provider type="java"
scope="Application"
methods="getInfo envoiDocument">
<isd:java class="GIsoap.exemple1.ImprimanteHP" static="false"/>
</isd:provider>
<isd:faultListener>org.apache.soap.server.DOMFaultListener</isd:faultListener>
<isd:mappings>
<isd:map encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:x="urn:imprimanteHP-demo" qname="x:ImpInfos"
javaType="GIsoap.exemple1.ImpInfos"
java2XMLClassName="org.apache.soap.encoding.soapenc.BeanSerializer"
xml2JavaClassName="org.apache.soap.encoding.soapenc.BeanSerializer"/>
<isd:map encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:x="urn:imprimanteHP-demo" qname="x:TacheInfos"
javaType="GIsoap.exemple1.TacheInfos"
java2XMLClassName="org.apache.soap.encoding.soapenc.BeanSerializer"
xml2JavaClassName="org.apache.soap.encoding.soapenc.BeanSerializer"/>
</isd:mappings>
</isd:service>
Le descripteur de déploiement pour notre service d’imprimante contient cinq éléments
qui nous devons regarder. Le premier élément est l'élément service, qui définit deux
attributs, le namespace de XML et l'identification unique du service à déployer.
L'identification définie dans l'élément de service doit être unique, puisque cet attribut est
employé pour identifier un service publié avec SOAP.
Le prochain élément que nous devons examiner est l'élément provider. Il définit
l’implémentation réelle du service de SOAP, grâce à trois attributs, dont chacun est défini
comme suit:
type
Définit le type d'exécution du service de SOAP. Nous avons défini notre service
comme service Java.
scope
Définit le cycle de vie du service de SOAP. Les valeurs possibles sont page, scope,
session, et application. Ces valeurs correspondent directement avec celles définies par
les spécifications de JSP.
methods
Définit les noms des méthodes qui peuvent être appelées sur cet objet de service.
Cette liste doit être une liste de noms de méthode séparés par un espace
java
SOAP – Simple Access Protocol
29
Cet élément contient un attribut simple, la classe, qui appelle la classe entièrement
qualifiée du service appelé.
mappings
Cet élément annonce tous les objets que nous avons serialisés. Les attributs
java2XMLClassName et xml2JavaClassName indiquent respectivement une classe
pour convertir de Java en XML et de XML en Java.
! Publication du service
Pour publier le service il suffit d’exécuter la commande suivante :
javaorg.apache.soap.server.ServiceManagerClient
http://localhost:8080/soap/servlet/rpcrouter deploy
DeploymentDescriptor.xml
ii)
Création d’un client soap
Maintenant que nous avons définit le service et qu’on l’a déployé, écrivons un client qui
exécutera une des méthodes du service. Le projet de SOAP d'Apache fournit une API côté
client qui permet de créer des clients de manière simple.
Voici par exemple le client qui imprime un fichier sur l’imprimante HP.
SOAP – Simple Access Protocol
30
package GIsoap.exemple1;
import
import
import
import
import
import
import
import
import
java.io.*;
java.util.*;
java.net.*;
org.w3c.dom.*;
org.apache.soap.util.xml.*;
org.apache.soap.*;
org.apache.soap.encoding.*;
org.apache.soap.encoding.soapenc.*;
org.apache.soap.rpc.*;
public class Imprime {
public static void main(String[] args) throws Exception {
if (args.length != 2) {
System.err.println("Usage:");
System.err.println(" java " + Imprime.class.getName() + "SOAP-router-URL" +
"fichier");
System.exit (1);
}
URL url = new URL(args[0]);
String nomfic = args[1];
SOAPMappingRegistry smr = new SOAPMappingRegistry();
BeanSerializer beanSer = new BeanSerializer();
// Map the types.
smr.mapTypes(Constants.NS_URI_SOAP_ENC,
new QName("urn:imprimanteHP-demo", "TacheInfos"),
TacheInfos.class, beanSer, beanSer);
// Build the call.
Call call = new Call();
call.setSOAPMappingRegistry(smr);
call.setTargetObjectURI("urn:ImprimanteHP");
call.setMethodName("envoiDocument");
call.setEncodingStyleURI(Constants.NS_URI_SOAP_ENC);
Vector params = new Vector();
params.addElement(new Parameter("n", String.class, nomfic, null));
call.setParams(params);
// Invoke the call.
Response resp;
try {
resp = call.invoke(url, "");
}
catch (SOAPException e) {
System.err.println("Caught SOAPException (" + e.getFaultCode() + "): " +
e.getMessage());
return;
}
if (!resp.generatedFault()) {
Parameter ret = resp.getReturnValue();
Object value = ret.getValue();
TacheInfos tache = (TacheInfos) value;
if (tache!=null)
System.out.println("\nImpression envoyée sur HP" + ", tâche " +
tache.getTacheCourante() + ", taille "+ tache.getTailleFichier() + " : "+ nomfic);
else
System.out.println("I don't know.");
}
else {
Fault fault = resp.getFault();
System.err.println("Generated fault: " + fault);
}
}
}
SOAP – Simple Access Protocol
31
Ce client suit un processus simple qui est commun à la plupart des clients RPC SOAP. Il
crée d'abord une URL mettant en référence le rpcrouter (que nous avons passé en argument)
sur le localhost de serveur de HTTP.
URL url = new URL(args[0]);
(http://localhost:8080/soap/servlet/rpcrouter)
Ensuite nous avons besoin que le client sache quels serializer et deserializer employer. C’est
que la classe SOAPMappingRegistry permet. La méthode mapTypes() prend en entré une
chaîne d’ encodage, et des informations sur le type de paramètre que devra utiliser une
sérialisation particulière. D'abord, un QName est fourni. Vous devez indiquer la même URN
ici, ainsi que le nom local de l'élément (dans ce cas-ci "TacheInfos"), puis de classe Java à
sérialiser (TacheInfos.class), et finalement l’instance de la classe nécessaire à la serialisation
et à la desérialisation. Dans le cas du BeanSerializer, la même instance fonctionne pour tous
les deux. Une fois que tout ceci est indiqué dans l'enregistrement, il ne reste plus qu’a en
informer l’objet call par la méthode setSOAPMapping-Registry().
SOAPMappingRegistry smr = new SOAPMappingRegistry();
BeanSerializer beanSer = new BeanSerializer();
// Map the types.
smr.mapTypes(Constants.NS_URI_SOAP_ENC,
new QName("urn:imprimanteHP-demo", "TacheInfos"),
TacheInfos.class, beanSer, beanSer);
// Build the call.
Call call = new Call();
call.setSOAPMappingRegistry(smr);
La prochaine étape exécutée par le client est de créer une instance de
org.apache.soap.rpc.RPCMessage.Call. L'objet call est l'interface principale utilisée lors de
l’exécution d ‘une invocation RPC SOAP.
Pour employer l'objet call, il faut lui indiquer quel service nous voulons utiliser. Nous faisons
ceci en appelant setTargetObjectURI, et en lui passant le nom du service que nous voulons
exécuter. Nous avons alors placé le nom de la méthode de service que nous voulons exécuter
en utilisant la méthode setMethodName().
La prochaine étape est d’indiquer le modèle d‘encodage utilisé dans l’appel RPC. L'étape
finale est d'ajouter les paramètres attendus en exécutant la méthode demandée. Ceci est fait
en créant un vecteur d‘objets parameter et en les ajoutant à l'objet call en utilisant la méthode
setParams().
call.setTargetObjectURI("urn:ImprimanteHP");
call.setMethodName("envoiDocument");
call.setEncodingStyleURI(Constants.NS_URI_SOAP_ENC);
Vector params = new Vector();
params.addElement(new Parameter("n", String.class,
nomfic, null));
call.setParams(params);
La prochaine étape exécutée par le client est d'appeler la méthode de service qui nous
intéresse. Ceci est fait en utilisant invoke() avec l’ URL que nous avons créé plus tôt.
SOAP – Simple Access Protocol
32
resp = call.invoke(url, "");
La valeur de retour de la méthode invoke() est un objet response. L'objet response renvoie un
code d'erreur et la valeur retournée de la méthode exécutée du service. On peut vérifier si
erreur s’est produite en appelant la méthode generatedFault(). Cette méthode renverra vrai s'il
une erreur est retournée; on obtient l’erreur par la méthode getFault(). Si le generatedFault()
renvoie faux, on peut alors obtenir la valeur retournée dans l'objet response, en utilisant la
méthode Response.getReturnValue().
Dans notre exemple on voit que la méthode imprime peut générer une exception
TacheRefusee. Cependant nous n’avons pas trouvé comment rattrapé cette exception du côté
client d’un manière correcte c’est à dire sans analyser la chaîne de caractères qui nous est
fournit par getFaultString().
b) Exemple 2 : le gestionnaire d’impression
Dans cet exemple nous voulons imprimer sur des imprimantes : HP ou CANON.
Dans la version CORBA, le gestionnaire d’impression crée un objet CORBA pour
chaque imprimante. Ensuite le client imprime sur l’imprimante désiré en obtenant la référence
de l’objet par un fichier ou un service de nommage. Avec SOAP une telle approche n’est pas
possible. Du moins pas par les références. On pourrait faire un service distinct pour chaque
imprimante, mais ceci reviendrait à récréer l exemple 1 pour l’imprimante CANON et
indiquer le bon URN au client en fonction de l’imprimante choisi. Mais une meilleure
solution consiste à créer un service que l’on appellera « GestionnaireImpression » qui va jouer
le rôle de proxy. Les imprimantes seront adressé par un nom et le proxy appellera la méthode
demandée de l’imprimante choisie.
HP
Imprimante.class
Imprime
SOAP (http)
GestionnaireImpression.class
GetInfos
(Proxy)
Clients
Service
Imprimante.class
CANON
Figure 2
Voici donc la forme du gestionnaire d’impression :
SOAP – Simple Access Protocol
33
package GIsoap.exemple2;
import java.util.*;
public class GestionnaireImpression
{
private Hashtable imprTable = new Hashtable();
public GestionnaireImpression()
{
imprTable.put("canon", new Imprimante("canon"));
imprTable.put("hp", new Imprimante("hp"));
}
public ImpInfos getInfo(String nomimp)
{
Imprimante imp=(Imprimante) imprTable.get(nomimp);
return imp.getInfo();
}
public TacheInfos envoiDocument( String nomimp, String nomfic)
throws TacheRefusee
{
Imprimante imp=(Imprimante) imprTable.get(nomimp);
return imp.envoiDocument(nomfic);
}
}
Et voilà un client :
SOAP – Simple Access Protocol
34
package GIsoap.exemple2;
import
import
import
import
import
import
import
import
import
java.io.*;
java.util.*;
java.net.*;
org.w3c.dom.*;
org.apache.soap.util.xml.*;
org.apache.soap.*;
org.apache.soap.encoding.*;
org.apache.soap.encoding.soapenc.*;
org.apache.soap.rpc.*;
public class Imprime {
public static void main(String[] args) throws Exception {
if (args.length != 3) {
System.err.println("Usage:");
System.err.println(" java " + Imprime.class.getName() +
"SOAP-router-URL" + "imprimante" + "fichier");
System.exit (1);
}
URL url = new URL(args[0]);
String nomimp = args[1];
String nomfic = args[2];
SOAPMappingRegistry smr = new SOAPMappingRegistry();
BeanSerializer beanSer = new BeanSerializer();
// Map the types.
smr.mapTypes(Constants.NS_URI_SOAP_ENC, new QName("urn:gestionimprimante-demo",
"TacheInfos"), TacheInfos.class, beanSer, beanSer);
// Build the call.
Call call = new Call();
call.setSOAPMappingRegistry(smr);
call.setTargetObjectURI("urn:GestionImprimante");
call.setMethodName("envoiDocument");
call.setEncodingStyleURI(Constants.NS_URI_SOAP_ENC);
Vector params = new Vector();
params.addElement(new Parameter("nomimp", String.class, nomimp, null));
params.addElement(new Parameter("nomfic", String.class, nomfic, null));
call.setParams(params);
// Invoke the call.
Response resp;
try {
resp = call.invoke(url, "");
}
catch (SOAPException e) {
System.err.println("Caught SOAPException (" + e.getFaultCode() + "): " +
e.getMessage());
return;
}
if (!resp.generatedFault()) {
Parameter ret = resp.getReturnValue();
Object value = ret.getValue();
TacheInfos tache = (TacheInfos) value;
if (tache!=null)
System.out.println("\nImpression envoyée sur " + nomimp + ", tâche " +
tache.getTacheCourante() + ", taille "+ tache.getTailleFichier() + " : "+ nomfic);
else
System.out.println("I don't know.");
}
else {
Fault fault = resp.getFault();
System.err.println("Generated fault: " + fault);
}
}
}
SOAP – Simple Access Protocol
35
c) Exemple 3 : le gestionnaire d’impression et WSDL
Dans les exemples précédent nous avons vu que l’appel de l’objet distant dans le client
n’était pas tout à fait transparente. En effet il faut mettre tous les paramètres dans un vecteur
en indiquant leur types, puis positionné la méthode que l’on souhaite appeler et enfin faire
invoke.
L’idée est donc cette fois ci de disposer du côté client d’un proxy qui nous rendrait les
appels transparents. D’autre part ce proxy peut être générée automatiquement.
Pour cela il faut dans premier temps créer un fichier WSDL qui va décrire le service
d’une manière indépendante du langage qui l’implémente. Puis à partir du fichier WSDL il
faut générer le proxy client (en java dans notre cas).
HP
Imprimante.class
Imprime
SOAP (http)
Gestionnaire
ImpressionProxy.class
Gestionnaire
Impression.class
GetInfos
Imprimante.class
Clients
Service
CANON
Figure 3
d) Exécution des exemples
Aller dans le répertoire GIsoap et exécuter une seule fois pour tout les exemples :
« . ./setclasspath »
Puis dans chaque répertoire d’exemple :
« ./testit.sh »
SOAP – Simple Access Protocol
36
Bibliographie
1. Articles Généraux sur SOAP
! Articles sur SOAP, tests d’implémentations et exemples de mise en œuvre,
http://www.soapuser.com/
! Tutoriel WSDL:
http://www.learnxmlws.com/tutors/wsdl/wsdl.aspx
! Standard SOAP par le W3C:
http://www.w3.org/TR/SOAP/
2. Implémentations et installation
! Une liste d’implémentations sur Soapware.org :
http://www.soapware.org/directory/4/implementations
! XML Apache Project:
http://xml.apache.org
! Apache SOAP:
http://xml.apache.org/soap
! NuSOAP:
http://dietrich.ganx4.com/nusoap/
! SOAP::Lite:
http://www.soaplite.com
! Installer Perl sans être super-utilisateur :
http://www.perl.com/pub/a/2002/04/10/mod_perl.html?page=1
3. Divers outils pour SOAP
! Outils AXIS :
http://xml.apache.org/axis/index.html
! Outils SOAP en ligne:
http://www.soapclient.com/SoapTools.html
4. Exemples de Web Services
! APIs web Google:
http://www.google.com/apis/index.html
! Xmethods:
http://www.xmethods.com/
SOAP – Simple Access Protocol
37

Documents pareils

Les web services : connecter des applications

Les web services : connecter des applications langages de programmation différents. Ils le font en reprenant certaines principes du Web (transport sur HTTP, formatage en XML) mais en mettant l’accent sur la communication entre applications, pa...

Plus en détail