Introduction
SOAP représente l’acronyme de Simple Object Access Protocol (en français, Protocole Simple d’Accès aux Objets). En fait, il s’agit essentiellement d’un protocole d’échanges d’informations au sein d’une architecture distribuée, et qui présente les caractéristiques générales suivantes :
- ce protocole est écrit en XML
- il supporte les services concernant les appels de procédure distante (Remote Procedure Call) aussi bien que les services d’échange de messages (services)
- il est principalement déployé au-dessus du protocole de transport
HTTP
- il est indépendant des plate-formes (platform-independant )
- il est indépendant des langages (language-independent )
Le fait que SOAP soit en XML (et donc qu’il soit un protocole basé sur du texte) est fondamental, car il rend SOAP beaucoup plus attractif (notamment en termes de débuggage) que d’autres protocoles tels que IIOP
(Inter-ORB Protocol , assurant la communication entre objets JAVA et CORBA), ORPC
(Object Remote Procedure Call) et JMRP
(Java Remote Method Protocol utilisé par RMI
), ces trois protocoles reposant sur des flux binaires, et donc plus difficiles à gérer.
Présentation générale de SOAP
Service RPC
Dans le scénario RPC, SOAP agit simplement à la manière d’un système XML-RPC plus flexible, facilitant notamment la gestion des erreurs ainsi que la transmission de types complexes sur le réseau : un client invoque une procédure distante sur un serveur se trouvant quelque part, puis reçoit une forme de réponse.
Dans ce tutoriel, un scenario est proposé à des fins de test :
- récupération des variables globales d’une base MySQL sur le serveur distant (
show variables like 'variable%'
etshow processlist
) par SOAP RPC (Remote Procedure Call)
La présentation générale de SOAP sera effectuée sur la base du scénario récupérant une variable globale du serveur MySQL distant.
Soit l’interface JAVA :
public interface GetMySQLInfosinXML
{
public String GetMySQLVariable(String my_Variable)
}
Un client appelant la méthode GetMySQLVariable
avec une variable déterminée attend de recevoir un message venant du serveur donnant la valeur pour la variable MySQL indiquée. SOAP consiste basiquement à sérialiser l’appel de méthode et à l’envoyer vers la machine distante, tout ceci via XML. En supposant que nous voulions simuler l’appel de la méthode GetMySQLVariable("version")
, on pourrait intuitivement proposer le message suivant :
<GetMySQLInfosinXML>
<GetMySQLVariable>
<my_Variable>version</my_Variable>
</GetMySQLVariable>
</GetMySQLInfosinXML>
Le nom de l’interface est le nœud racine du message, la méthode et le paramètre sont également transformés en nœuds.
La réponse renvoyée par le serveur pourrait être quant à elle, toujours dans la même logique, de la forme suivante :
<GetMySQLInfosinXML>
<GetMySQLVariableResponse>
<my_VariableValue>4.1.0-alpha-max-nt</my_VariableValue>
</GetMySQLVariableResponse>
</GetMySQLInfosinXML>
Le nœud racine est toujours l’interface GetMySQLInfosinXML
, mais cette fois le nœud fils consiste en la concaténation du nom et de la méthode et de la chaîne Response
.
L’enveloppe SOAP-RPC
Ce qui précède peut-être considéré comme la mouture d’un service RPC SOAP. En fait, voilà à quoi ressemble une véritable requête SOAP, et les quelques modifications supplémentaires apportées pour le tutoriel :
|
Et voilà ce que serait une réponse renvoyée par le serveur :
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<SOAP-ENV:Body>
<ns1:GetMySQLVariableResponse xmlns:ns1="GetMySQLInfosinXML"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<return xsi:type="xsd:string">4.0.1-alpha-max-nt</return>
</ns1:GetMySQLVariableResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
L’ensemble du message XML est contenu dans un élément de plus haut niveau
(top-level element) <Envelope>
, associé à l’espace de nommage
http://schemas.xmlsoap.org/soap/envelope
.
Cet élément est obligatoire, et doit correspondre à l’espace de nommage
sus-cité. Si un serveur SOAP reçoit une requête qui référence un autre espace de nom, il rejettera
alors cette requête avec un code VersionMismatch
dans l’élément
<faultcode>
.
Le premier élément fils de <Envelope>
est l’élément <Header>
,
optionnel (d’ailleurs non pris en charge par l’implémentation Apache de SOAP).
Le but principal d’un tel élément est de fournir des extensions au protocole,
n’ayant pas directement à voir avec telle ou telle méthode spécifiée, mais
apportant plutôt des informations contextuelles comme l’identifiant de
transactions et/ou des informations relatives à la sécurité
<SOAP-ENV:Header>
<transaction
xmlns="http://sitexml.com/articles">
<id>123455-4543544</id>
</transaction>
</SOAP-ENV:Header>
Vient ensuite l’élément <BODY>
qui doit être un fils direct de
l’élément <Envelope>
. Si un en-tête est présent, alors le corps doit
immédiatement le suivre. On remarque ici, précisément à propos de l’appel RPC, que le nom de l’interface (i.e. GetMySQLInfosinXML
)
n’est pas le nom d’un nœud comme nous l’avions auparavant approximé, mais que celui-ci est référencé dans un espace nommé, ns1
.
<SOAP-ENV:Body>
<ns1:GetMySQLVariable xmlns:ns1="GetMySQLInfosinXML"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<my_Variable xsi:type="xsd:string">version</my_Variable>
</ns1:GetMySQLVariableRequest>
</SOAP-ENV:Body>
On note également la valeur de l’attribut encodingStyle
, égale à
http://schemas.xmlsoap.org/soap/encoding/
, informant le serveur de l’encodage à
utiliser afin de sérialiser/désérialiser la méthode.
L’enveloppe d’un message SOAP
L’anatomie d’un message SOAP est plus simple que celle d’un service SOAP RPC. Elle consiste eseentiellement en:
- l’encapsulation (wrapping) du message XML
- l’inclusion du
body
SOAP dans l’enveloppe SOAP - l’ajout facultatif d’un
Header
au sein de cette même enveloppe
Ainsi, si le document XML d’origine à envoyer est le suivant :
|
sa mise en conformité avec la spécification SOAP Messaging ressemblera à ceci:
<xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope
xmlns:SOAP="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<SOAP-ENV:Header>
...
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<OrdreAchat
xmlns="urn:planetexml-articles">
<livraison pays="FR">
<nom>Paul Durand</nom>
<rue>14 rue des Roses</rue>
<ville>Paris</ville>
<code_postal>75011</code_postal>
</livraison>
<articles>
<article>
<type>livre</type>
<titre>La genealogie de la morale</titre>
<quantite>3</quantite>
<prix>3.00</prix>
<commentaire>Livraison rapide SVP!</commentaire>
</article>
</articles>
</OrdreAchat>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Fault
Le fait d’utiliser SOAP ne garantit malheureusement pas le fait que les
requêtes soient toujours couronnées de succès. Les choses peuvent mal se passer
en différents moments du processus de traitement. Le serveur renvoie alors une
réponse spécifiant un message d’erreur au sein d’un élément <Fault>
, fils
direct de <Body>
:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<SOAP-ENV:Body>
<Fault>
<faultcode>Server</faultcode>
<faultstring>service:'urn:helloworld' unknown<falutstring>
<faultactor>/soap/servlet/rpcrouter</faultactor>
</Fault>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Sans exception, l’élément <Fault>
doit obligatoirement contenir un
élément <faultcode>
ainsi qu’un élément <faultstring>
. Le premier
consiste en un code permettant d’identifier la nature du problème, et dont la
liste est définie par la spécification SOAP (notamment le code VersionMismatch
dont
il a été question précédemment, indiquant la présence d’un espace de nom
erronné, ou le code Client
, indiquant que le message de requête n’était pas
correctement formé ou ne contenait pas les informations appropriées en vue
d’être validé, etc.). Le deuxième élément <faultstring>
est quant à lui
destiné à une lecture humaine, et explicite plus clairement la cause de
l’erreur: dans l’exemple ci-dessus, le serveur est incapable de trouver le
service identifié par l’URN helloworld
, celui-ci n’ayant vraisemblablement pas
été déployé.
La liaison au protocole (SOAP Protocol Binding)
Dans le cadre de cette présentation générale, il reste à parler d’un dernier
élément, qui est la façon dont un message SOAP est lié au protocole sur lequel
il se déploie. Bien qu’il soit possible d’utiliser SOAP avec d’autres
protocoles que HTTP
(SMTP, FTP
, etc.), la documentation se concentre sur HTTP
,
qui reste le protocole en final le plus largement utilisé.
En premier lieu, il vaut la peine de souligner que, ainsi que le note la
spécification SOAP Version 1.2, le fait que SOAP se déploie au-dessus de HTTP
ne signifie pas qu’il remplace ou se substitue à quoi que ce soit dans la sémantique
du protocole, mais plutôt qu’il en hérite, à son grand avantage ("Carrying SOAP
in HTTP does not mean that SOAP overrides existing semantics of HTTP, but
rather than"
).
La définition d’une liaison HTTP
concerne trois parties HTTP: la
requête HTTP
, la réponse HTTP
, et enfin le cadre d’extension HTTP
. Dans tous
les cas, le media type "text/xml"
doit être utilisé lors de l’encapsulation de
messages SOAP dans des échanges HTTP
.
En ce qui concerne la requête HTTP
, la grande majorité des liaisons se fait
avec la méthode de requête HTTP POST
. Le champ d’en-tête de requête http
SOAPAction
(SOAPAction HTTP request header
) peut être utilisé afin d’indiquer
la cible de requête SOAP HTTP
. La valeur qui doit renseigner un tel champ
représente l’URI de la cible. SOAPAction
sert notamment au filtrage des
requêtes par les firewalls.
Une valeur de chaîne vide signifie que la cible du message SOAP est fournie par
l’URI de la requête HTTP
(on verra que c’est comme cela que fonctionne
l’implémentation SOAP d’Apache), tandis que l’absence pure et simple de valeur
indique qu’il n’y a pas de cible explicite du message. Voici un exemple
d’en-tête de requête SOAP HTTP
:
POST /soap/servlet/rpcrouter HTTP/1.1
Host: localhost
Content-Type: text/xml; charset="utf-8"
Content-Length: 345
SOAPAction: "http://electrocommerce.org/">
<env:Envelope xmlns:env="http://www.w3.org/2001/06/soap-envelope">
...
</env:Envelope>
En ce qui concerne la réponse HTTP
, SOAP suit la sémantique des codes de
statut HTTP
(HTTP Status codes
) pour communiquer des informations de statut sur
HTTP
.
Par exemple, un code de statut 2xx indique que la requête du client incluant le
composant SOAP a été reçu avec succès, correctement interprété, accepté, etc.
Si une erreur se produit pendant le traitement de la requête, le serveur SOAP
HTTP
doit renvoyer une réponse HTTP 500 "Internal Server Error"
et inclure un
élément SOAP fault
dans le message SOAP de retour
La réponse au message SOAP précédent a la forme suivante:
HTTP/1.1 200 OK
Content-Type: text/xml charset="utf-8"
Content-Length: 323
<env:Envelope xmlns:env="http://www.w3.org/2001/06/soap-envelope">
...
</env:Envelope>
Enfin, un message SOAP peut être utilisé avec le cadre d’extension http
(téléchargeable à l’adresse http://www.w3.org/Protocols/HTTP/ietf-http-ext ) ,
dans le but d’identifier la présence et la destination d’une requête HTTP
. La
principale caractéristique de cette extension qui dépasse largement les seuls
besoins SOAP est de définir un mécanisme afin d’étendre dynamiquement la
fonctionnalité des clients et serveurs HTTP
par l’utilisation des espaces de
nom. Cela fonctionne de la façon suivante:
- Les concepteurs se mettent d’accord sur une extension et assignent à
cette extension une URI globale unique. Pour SOAP, il s’agit de l’adresse
http://schemas.xmlsoap.org/soap/envelope
- Un client ou un serveur implémentant une telle extension déclare son
utilisation via cet URI dans le header
HTTP
. La déclaration de l’URI et l’espace de nom qui lui est associé est effectuée conformément à l’HTTP Extension Framework
- L’application
HTTP
peut alors implémenter le comportement souhaité sans risque de conflit
La même requête que celle vue précédemment a la forme suivante, une fois étendue:
M-POST /soap/servlet/rpcrouter HTTP/1.1
Man: "http://schemas.xmlsoap.org/soap/envelope"; ns=144
Host: localhost
Content-Type: text/xml; charset="utf-8"
Content-Length: 345
144-SOAPAction: "http://electrocommerce.org/">
<env:Envelope xmlns:env="http://www.w3.org/2001/06/soap-envelope">
...
</env:Envelope>
La première différence entre une requête SOAP HTTP
classique et une requête SOAP HTTP
étendue
est la mention: M-POST
plutôt que POST
. M-POST
définit une requête
HTTP
obligatoire (mandatory HTTP request
): on qualifie ainsi une requête si
celle-ci inclut au moins une déclaration de la forme suivante:
Man:"http://schemas.xmlsoap.org/soap/envelope"; ns=144
Dés lors, le reste de l’en-tête HTTP
doit contenir au moins une declaration
d’extension pour l’URI spécifiée.
Dans notre cas, il s’agit de la ligne suivante: 144-SOAPAction:
"http://electrocommerce.org/">
On note que SOAPAction
est préfixé par 144, préfixe utilisé pour l’URI
spécifié dans l’élément d’en-tête Man
.
Configuration et utilisation de SOAP Apache
Installation et configuration
L’étape préliminaire est d’inclure à la fois dans son CLASSPATH
côté client
et dans le CLASSPATH
du moteur de servlet les librairies mail.jar
et activation.jar
.
La librairie mail.jar est requise pour la prise en charge du protocole SMTP
. Pour télécharger ces 2 librairies :
Un parseur compatible JAXP
, sensible aux espaces de nom, est nécessaire : Apache Xerces v1.1.2 ou versions supérieures fait très
bien l’affaire.
Les archives mail.jar
et activation.jar
sont déjà fournies avec le serveur
Tomcat 4.0.1. Dans la suite de la documentation $TOMCAT_DIR
ou %TOMCAT_DIR%
selon le système d’exploitation désignera le répertoire d’installation de
Tomcat.
Nous utilisons dans ce tutoriel SOAP Apache, une des trois majeures implémentations de la spécification SOAP, la seconde étant toujours proposée par la fondation Apache sous le nom d’Apache Axis et la dernière étant le fait de Microsoft.
SOAP Apache est disponible en téléchargement sur le site de la fondation Apache
à l’adresse : http://xml.apache.org/dist/soap/version-2.2.
SOAP Apache implémente un composant côté client, ainsi qu’un composant côté serveur. Le
fichier à télécharger pour les plate-formes Windows est soap-bin-2.2.zip
et
soap-bin-2.2.tar.gz
pour les plate-formes Linux. Une fois ceci fait, il ne
reste plus qu’à extraire la ressource où vous le voulez, par exemple avec
l’utilitaire Winzip.
L’étape la plus délicate consiste à présent à déployer SOAP dans le moteur de servlet utilisé, ici Tomcat 4.0.1. Pour cela, deux méthodes sont possibles:
- La plus facile: la distribution Apache de SOAP inclut une archive Web à
l’adresse
/soap-2_2/webapps/soap.war
. Déplacer cette archive dans le répertoirewebapps
de Tomcat et démarrer ce dernier. Il s’agit de cette installation qui a été choisie dans le contexte de cette documentation. Lors de cette opération, un sous répertoiresoap
est automatiquement déployé dans le répertoireTOMCAT_DIR/webapps
. Dans la suite de la documentation$SOAP_INSTALL
ou%SOAP_INSTALL%
selon le système d’exploitation désignera le répertoire d’installation de soap 2.2 dans le moteur de servlets Tomcat. - Seconde méthode : créer un nouveau
<Context>
dans le fichierserver.xml
installé dans le répertoire%TOMCAT_DIR%/conf
ou$TOMCAT_DIR/conf
, comme suit:<Context path="/soap" docBase="chemin-de-apache-soap/webapps/soap" debug="1" reloadable="true"> </Context>
Dans ce cas-là, il faut veiller à bien mettre toutes les archives contenues
dans le dossier /lib
de la distribution dans la variable CLASSPATH
.
Une solution simple pour préparer l’environnement côté client et côté serveur
consiste à appliquer la variable CLASSPATH
avec les scripts ci-dessous :
DOS Windows :
set CLASSPATH=%CLASSPATH%; %TOMCAT_DIR%\common\lib\mail.jar;%TOMCAT_DIR%\common\lib\activation.jar;
%SOAP_INSTALL%\WEB-INF\classes
Unix / Linux :
CLASSPATH=$CLASSPATH;$TOMCAT_DIR/common/lib/mail.jar;$TOMCAT_DIR/common/lib/activation.jar;
$SOAP_INSTALL/WEB-INF/classes
export CLASSPATH
Test de SOAP
Pour tester si le serveur SOAP est correctement configuré, pointer le
navigateur à l’adresse
http://<SERVER>:<PORT>/soap/servlet/rpcrouter
, après avoir pris
bien soin d’avoir démarré Tomcat, le port à spécifier correspond à celui
configuré pour Tomcat. La réponse ci-dessous devrait alors être affichée dans
le navigateur :
Adresse : http://localhost:9002/soap/servlet/rpcrouter
SOAP RPC ROUTER
Sorry, I don't speak via HTTP GET - you have to use HTTP POST to talk
to me.
Ce message contrairement à son apparence indique que le serveur SOAP fonctionne correctement.
Un autre test simple consiste à solliciter la page d’administration de SOAP
Apache (compte : admin
) : http://<SERVER>:<PORT>/soap/admin/index.html
Déploiement des services SOAP
Déploiement logique d’un service SOAP
Deux méthodes peuvent être envisagées pour le déploiement logique d’un service SOAP :
- via l’interface graphique SOAP Apache.
- via la classe Java
org.apache.soap.server.ServiceManagerClient
en ligne de commande.
L’utilisation de la classe Java org.apache.soap.server.ServiceManagerClient
est
résumée ci-dessous :
Usage: java org.apache.soap.server.ServiceManagerClient [-auth username:password] url operation arguments
where
username and password is the HTTP Basic authentication info
url is the Apache SOAP router's URL whose services are managed
operation and arguments are:
deploy deployment-descriptor-file.xml
list
query service-name
undeploy service-name
Des exemples concrets seront donnés dans les paragraphes qui suivent.
Déploiement physique d’un service SOAP
La façon la plus élégante d’implémenter physiquement un service SOAP sur le
serveur consiste à utiliser l’outil ANT
, toujours de la fondation Apache. Mais
pour un service modeste, la création manuelle de l’arborescence sur le serveur
est envisageable.
Il est possible de créer l’arborescence où l’on veut sur le disque dur, à
condition d’éditer le fichier server.xml
du dossier conf
de Tomcat. Le
plus simple cependant consiste à utiliser l’arborescence
webapps->soap->WEB-INF->classes
déjà mise en place au sein de Tomcat
après le déploiement de SOAP, et de lui adjoindre le nouveau dossier contenant
les classes propres au service SOAP à implémenter physiquement.
Le serveur Tomcat doit être redémarré pour la prise en charge du nouveau service SOAP.
Cas pratique SOAP RPC
Présentation du cas SOAP RPC
Voici schématiquement le cas pratique SOAP RPC :
Implémentation du service SOAP RPC côté serveur
Développement du service SOAP RPC
L’exemple simple ci-dessous de service SOAP interroge une base
de données MySQL avec la commande « show variables like 'param%'
» où param
est
le paramètre donné au service.
/*
* GetMySQLInfosinXML.java
*
* Classe de test SOAP RPC
*
*/
package com.sqlpac.soap;
import java.sql.*;
public class GetMySQLInfosinXML {
public String GetMySQLVariable(String my_Variable)
throws Exception {
try {
Class.forName("com.mysql.jdbc.Driver").newInstance();
Connection Conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/cgcam_db?user=root&password=");
Statement Stmt = Conn.createStatement();
ResultSet RS = Stmt.executeQuery("show variables like '"+my_Variable+"%'");
String ReturnValue = new String();
while(RS.next()) {
ReturnValue= RS.getString(2);
}
RS.close();
Stmt.close();
Conn.close();
return ReturnValue;
}
catch (SQLException E) {
String E_error = "Grave erreur..." + E.getMessage();
return E_error;
}
}
}
Création du fichier de description de déploiement GetMySQLInfosinXML.xml
Le fichier de description de déploiement de la classe Java GetMySQLInfosinXML
permet de déployer ce service SOAP avec ServiceManagerClient
<isd:service xmlns:isd="http://xml.apache.org/xml-soap/deployment"
id="urn:GetMySQLInfosinXML">
<isd:provider type="java" scope="Request" methods="GetMySQLVariable">
<isd:java class="com.sqlpac.soap.GetMySQLInfosinXML" static="false"/>
</isd:provider>
</isd:service>
Il est possible d’indiquer plusieurs méthodes dans la rubrique methods du fichier de déploiement, ces dernières doivent seulement être séparées par des espaces.
Déploiement logique du service SOAP RPC
Le service est implémenté logiquement avec la ligne de commande ci-dessous (ou via l’interface graphique d’administration de SOAP Apache selon les préférences) :
Dos :
C:\> java org.apache.soap.server.ServiceManagerClient %URL% deploy C:\Projets\Java\com\sqlpac\soap\GetMySQLInfosinXML.xml
Dans cette ligne de commande, %URL%
est une variable d’environnement
positionnée à la valeur suivante : http://localhost:9002/soap/servlet/rpcrouter
Si cela ne fonctionne pas, vérifier la variable CLASSPATH
utilisée pour retrouver les librairies java nécessaires.
Pour vérifier la bonne implémentation du service SOAP, deux commandes :
C:\> java org.apache.soap.server.ServiceManagerClient %URL% list
L’option list
affiche les services SOAP implémentés :
urn :GetMySQLInfosinXML
C:\> java org.apache.soap.server.ServiceManagerClient %URL% query urn:MySQLInfos
L’option query service-name
donne les paramètres de description du service
(notamment les paramètres spécifiés dans le document XML de description pour le
déploiement logique).
Déploiement physique du service SOAP RPC
Pour le déploiement physique du service SOAP, installer le
fichier compilé du service GetMySQLInfosinXML
(GetMySQLInfosinXML.class
) dans le
répertoire TOMCAT_DIR/soap/WEB-INF/classes/com/sqlpac/
. À l’issue de l’implémentation physique, redémarrer le serveur Tomcat.
Sollicitation du service SOAP RPC par un client Java
Une fois le service déployé sur le serveur, il faut créer le côté client
Java ClientGetMySQLInfosinXML
de SOAP Apache. Avant de regarder le code pas à pas,
sommairement les étapes à suivre lors de chaque appel SOAP-RPC sont les
suivantes :
- Créer l’appel SOAP-RPC
- Définir l’URI du service SOAP à utiliser
- Spécifier la méthode à invoquer
- Ajouter les paramètres de l’appel
- Définir les mises en correspondances de types pour les paramètres personnalisés
- Se connecter au service SOAP
- Recevoir et traiter la réponse
Code Java du client ClientGetMySQLInfosinXML
package com.sqlpac.soap;
import java.net.URL;
import java.util.Vector;
import java.util.Arrays;
import org.apache.soap.Constants;
import org.apache.soap.SOAPException;
import org.apache.soap.Envelope;
import org.apache.soap.Fault;
import org.apache.soap.rpc.Call;
import org.apache.soap.rpc.Response;
import org.apache.soap.rpc.Parameter;
public class ClientGetMySQLInfosinXML {
public static void main(String args[]) {
String nomMethode = "com.sqlpac.soap.ClientGetMySQLInfosinXML.main";
String url = "http://localhost:9002/soap/servlet/rpcrouter";
String uri = "urn:GetMySQLInfosinXML"; //mise en relation avec GetMySQLInfosinXML.xml
String methodeDistante = "GetMySQLVariable";
String my_Variable = "version";
if (args.length != 0) {
System.err.println("ClientGetMySQLInfosinXML: invoque un service SOAP.");
System.err.println("Usage: ClientGetMySQLInfosinXML <parameter>");
System.exit(1);
}
System.out.println(nomMethode + ": debut du test...");
try {
Call call = new Call();
Parameter param = new Parameter("my_Variable",my_Variable.getClass(),my_Variable,Constants.NS_URI_SOAP_ENC);
call.setTargetObjectURI(uri);
call.setMethodName(methodeDistante);
call.setParams(new Vector(Arrays.asList(new Parameter[] {
param
})));
Response reponse = call.invoke(new URL(url), "");
// Vérifie la réponse
if (reponse.generatedFault()) {
Fault faute = reponse.getFault();
System.out.println(nomMethode + ": appel a " + methodeDistante + " a retourne une faute!");
System.out.println(" code de la faute: " + faute.getFaultCode());
System.out.println(" cause de la faute: " + faute.getFaultString());
System.exit(1);
} else {
if (reponse.getReturnValue() != null) {
Object result = reponse.getReturnValue().getValue();
System.out.println("Méthode appelée :" + methodeDistante);
System.out.println("Type objet retourné :" + result.getClass() );
System.out.println("Valeur retournée :" + result );
}
}
}
catch (SOAPException exception) {
System.err.println(nomMethode + ": Erreur: capture d'exception " + exception);
}
System.out.println(nomMethode + ": Test correctement effectue!");
}
}
Packages à importer
package com.sqlpac.soap;
import java.net.URL;
import java.util.Vector;
import java.util.Arrays;
import org.apache.soap.Constants;
import org.apache.soap.SOAPException;
import org.apache.soap.Envelope;
import org.apache.soap.Fault;
import org.apache.soap.rpc.Call;
import org.apache.soap.rpc.Response;
import org.apache.soap.rpc.Parameter;
On commence par la traditionnelle importation des classes requises. La
classe Constants
définit des valeurs utiles comme le type d’encodage
utilisé dans l’appel. L’exception SOAPException
est envoyée par SOAP lorque
quelque chose se déroule mal, et la classe Fault
encapsule une
section SOAP:FAULT
dans la réponse.
Enfin, les classes rpc.*
construisent l’appel au service.
Appel du service SOAP RPC urn :GetMySQLInfosinXML
public class ClientGetMySQLInfosinXML {
public static void main(String args[]) {
String nomMethode = "com.sqlpac.soap.ClientGetMySQLInfosinXML.main";
String url = "http://localhost:9002/soap/servlet/rpcrouter";
String uri = "urn:GetMySQLInfosinXML"; //mise en relation avec GetMySQLInfosinXML.xml
String methodeDistante = "GetMySQLVariable";
String my_Variable = "version";
On définit ensuite un certain nombre de variables pour rendre le code plus
lisible par la suite. L’uri que l’on définit ici doit correspondre à
l’identifiant unique de notre service, renseigné soit manuellement à travers le
descripteur de déploiement GetMySQLInfosinXML.xml
, soit interactivement via
l’interface d’administration SOAP.
if (args.length != 0) {
System.err.println("ClientGetMySQLInfosinXML: invoque un service SOAP.");
System.err.println("Usage: ClientGetMySQLInfosinXML <parameter>");
System.exit(1);
}
System.out.println(nomMethode + ": debut du test...");
try {
Call call = new Call();
Parameter param = new Parameter("my_Variable",my_Variable.getClass(),my_Variable,Constants.NS_URI_SOAP_ENC);
Le nombre d’arguments donné au programme client est d’abord testé
Un objet call
pour l’appel RPC est créé puis un objet Parameter
pour l’argument my_variable
qui sera donné dans l’appel RPC. Les objets Parameter
sont utilisés à la fois par le client et le serveur. Le premier argument donné à l’objet Parameter
correspond
au nom de la variable, le second à son type, le troisième à la
variable qui le référence, et enfin le quatrième à l’encodage utilisé, ici
l’encodage SOAP standard.
call.setTargetObjectURI(uri);
call.setMethodName(methodeDistante);
call.setParams(new Vector(Arrays.asList(new Parameter[] {
param
})));
Response reponse = call.invoke(new URL(url), "");
Une fois l’URI du service défini via la méthode setTargetObjectURI
, on
spécifie le nom de la méthode invoquée avec
setMethodName
et les paramètres sont transmis avec
setParams
. Le service SOAP distant est enfin sollicité avec invoke()
. Le second
argument de cette méthode correspond à la valeur du champ SOAPAction
du Header
.
Comme celui-ci est ignoré par le serveur Apache, une valeur vide est
transmise.
Traitement de la réponse
// Vérifie la réponse
if (reponse.generatedFault()) {
Fault faute = reponse.getFault();
System.out.println(nomMethode + ": appel a " + methodeDistante + " a retourne une faute!");
System.out.println(" code de la faute: " + faute.getFaultCode());
System.out.println(" cause de la faute: " + faute.getFaultString());
System.exit(1);
} else {
if (reponse.getReturnValue() != null) {
Object result = reponse.getReturnValue().getValue();
System.out.println("Méthode appelée :" + methodeDistante);
System.out.println("Type objet retourné :" + result.getClass() );
System.out.println("Valeur retournée :" + result );
}
}
Si la réponse pose problème, une faute est générée, à la fois sous forme de
code et d’explication via respectivement les méthodes getFaultCode()
et
getFaultString()
(ces deux informations correspondent aux éléments
<faultcode>
et <code>
).
Dans le cas contraire, on récupère le paramètre de la réponse via la méthode
public Parameter getReturnValue()
, dont on récupère ensuite la valeur via la
méthode getValue()
.
On récupère également dans le message de la ligne de commande la classe du
paramètre renvoyé via la méthode classique getClass()
. On aurait pu tout aussi
bien utiliser la méthode getType()
associée à l’objet Parameter
.
Cas pratique SOAP Messaging
Présentation d’un cas SOAP Messaging
Voici schématiquement un cas pratique de SOAP Messaging
Dans ce cas pratique, les données d’une commande SQL sont renvoyées au client sous format XML, il est possible d’envisager un autre cas pratique où les données renvoyées au format XML correspondent au parsing d’un fichier de log côté serveur.
Le fichier XML renvoyé au client a la structure suivante :
<parameters>
<version>4.1.0-alpha-max-nt</version>
<parameter>value</parameter>
</parameters>