P
'
t
i
t
e
C
h
a
t
t
e
 
spacer~ SOME BABIES WERE DROPPED ON THEIR HEADS BUT YOU WERE CLEARLY THROWN AT A WALL Articles | Connexion
 
~Les appels de procédures distantes

 Présentation

Les appels de procédures distantes existent depuis très longtemps. Des technologies telles que CORBA, DCOM ou encore RMI offrent la possibilité de mettre en place des architectures distribuées très simplement. Les Services Web reprennent le principe en se basant sur XML.

Les implémentations actuelles des Services Web offrent deux technologies de Remote Procedure Call (RPC), SOAP-RPC et XML-RPC. La première repose bien évidemment sur les messages SOAP que nous connaissons. La seconde quant à elle offre des bibliothèques plus légères et plus simples à mettre en place que si nous utilisions SOAP.

 Sommaire


 XML-RPC

Une fois n'est pas coutume, la fondation Apache propose une bibliothèque de qualité sur le site http://ws.apache.org/xmlrpc/ que tout développeur pourra utiliser au cour de ses applications Java. Celle-ci, de faible taille (une soixantaine de ko), pourra être employée pour réaliser aussi bien des serveurs que des clients RPC. Le listing 1 présente le code source d'un servlet exposant les méthodes de la classe Articles au travers du Service Web "articles". L'ajout d'un service de procédure distante nécessite le simple ajout d'un "handler" au serveur. A l'aide d'une simple instruction, toutes les méthodes publiques de l'instance passée en paramètre à addHandler() pourront se voir invoquées. Cette même bibliothèque propose une application permettant de tester le servlet en exécutant la commande suivante :

java org.apache.xmlrpc.XmlRpcClient
http://localhost:8080/xmlrpc/invoke articles.getArticlesCount GBA
       
      
JextCopier dans Jext | Jext | Plugin Codegeek
Nous préfixons le nom de la méthode à exécuter avec le nom du service, et nous pouvons ajouter des paramètres, comme ici la chaîne "GBA". Si vous désirez réaliser les appels depuis votre code source, suivez l'exemple du listing 2. Une fois de plus, nous pouvons admirer la simplicité de XML-RPC qui, bien sur, ne se restreint pas à Java. Ainsi, à l'aide de la librairie Python xmlrpclib nous sommes en mesure de refaire exactement la même chose que précédemment :

from xmlrpclib import *
self.rpcServer = ServerProxy("http://localhost:8080/xmlrpc/invoke")
for thema in self.rpcServer.articles.getThemas():
  print "Un thème", thema
       
      
JextCopier dans Jext
Vous trouverez sur le CD-Rom une application intitulée NomadReader qui liste les articles du site http://progx.jext.org à l'aide de XML-RPC.


 SOAP-RPC

Malgré la concision des programmes basés sur XML-RPC, certains développeurs préféreront se tourner vers SOAP-RPC, qui bénéficie d'un support bien plus large et qui à l'avantage d'utiliser un protocole déjà connu. L'API sous-jacente se révèle un peu plus compliquée cette fois. Le listing 3 présente une invocation RPC réalisée avec l'implémentation de la fondation Apache. Pour que cet exemple fonctionne, nous devons déployer l'application Web soap.war dans Tomcat et le Service Web lui-même. Ce dernier point nécessite la rédaction d'un descripteur de service, au format XML. Un tel fichier permet de faire le lien entre l'interface du Service Web et les méthodes d'une classe Java. A l'instar de XML-RPC, ces dernières n'ont rien de particulier, même si on bénéficie de la possibilité de leur faire lever des exceptions de type SOAPException, ce qui conduira à l'émission d'une faute SOAP au client. Le listing 4 contient un descripteur de déploiement complet.

Celui-ci définit simplement à l'aide de la balise les méthodes exposées par le Service Web. La sous-balise permet pour sa part de signifier au serveur que le code se trouve dans une classe Java explicitement nommée, auquel le serveur doit avoir accès. Dans le listing 3, nous avons écrit l'instruction setTargetObjectURI(), permettant d'identifier le Service Web avec une URI au lieu d'un simple nom comme dans XML-RPC. Celle-ci a été définie dans le descripteur à l'aide de l'attribut id de la balise racine, . La dernière tâche consiste à enregistrer le descripteur auprès du serveur par l'entremise de la commande suivante :

java org.apache.soap.server.ServiceManagerClient
http://localhost:8080/soap/servlet/rpcrouter deploy Descripteur.xml
       
      
JextCopier dans Jext | Jext | Plugin Codegeek
Après invocation d'un service dûment installé et configuré, nous obtenons une instance de Response permettant pour sa part de savoir si l'invocation a fonctionné, et si oui quel en est le résultat. A la réception d'une réponse, il s'avère donc indispensable d'en vérifier la validité :

if (response.generatedFault())
{
  Fault fault = response.getFault();
  throw new Exception(fault.getFaultCode() + " " + fault.getFaultString());
}
       
      
JextCopier dans Jext
Le code de faute correspond dans ces quelques lignes aux types Client, Server, MustUnderstand, et VersionMismatch déjà évoqués. Enfin, nous pouvons récupérer la valeur renvoyée par la procédure :

Parameter result = response.getReturnValue();
Integer articlesCount = (Integer) result.getValue();
       
      
JextCopier dans Jext
La valeur se trouve encapsulée par la classe Parameter, que nous avons déjà utilisée pour préparer l'appel. Celle-ci conserve le résultat de l'exécution sous la forme d'une instance de Object, à charge du programmeur de réaliser la conversion explicite adéquate.

Le choix entre ces deux technologies se fera bien souvent en fonction des possibilités offertes par les serveurs à votre disposition. Il semble peu vraisemblable que vous puissiez avoir accès à des serveurs supportant XML-RPC d'origine. Heureusement, le déploiement d'un servlet Java permet de pallier cette limitation sans problème. Notons enfin que si XML-RPC se révèle bien plus facile d'accès que son homologue, il pèche par sa gestion des erreurs. Dans un environnement critique, il sera préférable de se tourner vers SOAP-RPC dont le système de faute apportera une certaine sécurité à vos applications.

public class XMLRPCServlet extends HttpServlet
{
  private XmlRpcServer xmlrpc;

  public void init(ServletConfig config) throws ServletException
  {
    xmlrpc = new XmlRpcServer();
    xmlrpc.addHandler("articles", new Articles());
  }

  public void doPost(HttpServletRequest req, HttpServletResponse res)
    throws ServletException, IOException
  {
    byte[] result = xmlrpc.execute(req.getInputStream());
    res.setContentType("text/xml");
    res.setContentLength(result.length);
    OutputStream output = res.getOutputStream();
    output.write(result);
    output.flush();
  }
}
       
      
JextCopier dans Jext
XmlRpcClient xmlrpc = new XmlRpcClient ("http://localhost:8080/xmlrpc/invoke");
Vector params = new Vector ();
params.addElement ("GBA");
String result = (String) xmlrpc.execute ("articles.getArticlesCount", params);
       
      
JextCopier dans Jext
Call call = new Call ();
String encodingStyleURI = org.apache.soap.Constants.NS_URI_SOAP_ENC;
call.setEncodingStyleURI(encodingStyleURI);
call.setTargetObjectURI ("urn:progx-articles");
call.setMethodName("getArticlesCount");
Vector parameters = new Vector ();
parameters.addElement (new Parameter("thema", String.class, "GBA", null));
call.setParams(parameters);
Response response = call.invoke(
  new URL("http://localhost:8080/soap/servlet/rpcrouter"), "");
       
      
JextCopier dans Jext
<isd:service xmlns:isd="http://xml.apache.org/xml-soap/deployment"
   id="urn:progx-articles">
  <isd:provider type="java" scope="Application"
    methods="getArticle getArticleAuthor getArticlesCount getArticleTitle getThemas">
    <isd:java class="Articles" />
  </isd:provider>
  <isd:faultListener>org.apache.soap.server.DOMFaultListener</isd:faultListener>
</isd:service>
       
      
JextCopier dans Jext


par Romain Guy
romain.guy@jext.org
http://www.jext.org
Dernière mise à jour : 14/10/2006



 
#ProgX©2005 Mathieu GINOD - Romain GUY - Erik LOUISE