<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" "dtd/xml/4.1.2/docbookx.dtd" [
<!ENTITY % afnic_custom SYSTEM "../lib/afnic-docbook.inc">
<!ELEMENT rfc EMPTY>
<!ATTLIST rfc num CDATA #IMPLIED>
<!ENTITY % local.para.char.mix "|rfc">
<!-- http://www.sagehill.net/xml/docbookxsl/ModularDoc.html#UsingXinclude --><!ELEMENT xi:include (xi:fallback)?>
<!ATTLIST xi:include xmlns:xi CDATA #FIXED "http://www.w3.org/2001/XInclude">
<!ATTLIST xi:include href CDATA #REQUIRED>
<!ATTLIST xi:include parse (xml | text) "xml">
<!ATTLIST xi:include encoding CDATA #IMPLIED>
<!ELEMENT xi:fallback ANY>
<!ATTLIST xi:fallback xmlns:xi CDATA #FIXED "http://www.w3.org/2001/XInclude">
<!-- Where are they allowed? --><!ENTITY % local.divcomponent.mix "| xi:include">
<!-- inside chapter or section elements                --><!-- inside para, programlisting, literallayout, etc.  --><!ENTITY % local.info.class "| xi:include">
<!-- inside bookinfo, chapterinfo, etc.                --><!ATTLIST book xmlns:xi CDATA #FIXED "http://www.w3.org/2001/XInclude">
<!ATTLIST article xmlns:xi CDATA #FIXED "http://www.w3.org/2001/XInclude">
<!ATTLIST chapter xmlns:xi CDATA #FIXED "http://www.w3.org/2001/XInclude">
<!ATTLIST section xmlns:xi CDATA #FIXED "http://www.w3.org/2001/XInclude">
<!-- $Id: afnic-docbook.inc,v 1.3 2003/08/07 09:35:14 bortzmeyer Exp $ --><!ENTITY ws "<foreignphrase>Web Services</foreignphrase>">
<!ENTITY uws "<foreignphrase>Web Service</foreignphrase>">
]>
<!-- $Id: web-services.db,v 1.9 2003/11/24 09:22:53 bortzmeyer Exp $ -->
<article xmlns:xi="http://www.w3.org/2001/XInclude" lang="fr">
  <title>Les &ws; : connecter des applications</title>
  <articleinfo>
    <author>
      <firstname>Stéphane</firstname>
      <surname>Bortzmeyer</surname>
      <affiliation>
	<orgname>AFNIC</orgname>
	<address><email>bortzmeyer@nic.fr</email></address>
      </affiliation>
    </author>
    <date>$Date: 2003/11/24 09:22:53 $</date>
    <copyright>
      <year>2003</year>
      <holder>AFNIC</holder>
    </copyright>
    <releaseinfo>$Id: web-services.db,v 1.9 2003/11/24 09:22:53 bortzmeyer Exp $</releaseinfo>
    <legalnotice>
<para>Ce document est distribué sous les termes de la <ulink url="http://www.gnu.org/licenses/licenses.html#FDL">GNU Free
      Documentation License</ulink>. <phrase lang="en">Permission is granted to copy, distribute and/or modify this document
      under the terms of the GNU Free Documentation License, Version 1.2
      or any later version published by the Free Software Foundation;
      with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.</phrase>
</para>
    </legalnotice>
  <abstract>
    <para>Faire interagir des programmes différents en
             réseau a toujours été une affaire complexe,
             notamment si on souhaite standardiser certains
             aspects de cette interaction (une sorte de
             couche à mi-chemin entre le Transport et les
             Applications, comme la défunte couche 5).</para>

             <para>Les &ws; sont un ensemble de
             protocoles qui permettent, au moins sur le
             papier, de faire communiquer (avec un
             protocole de haut niveau, pas juste des bits) des
             programmes tournant sur des machines
             différentes et écrits dans des 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, pas entre humains. </para>
             <para>Ils permettent donc de connecter différents
             composants du système d'information (y compris entre
             organisations différentes).      <remark><xref linkend="xml-rpc.ora"/><xref linkend="beep.rose"/><xref linkend="soap.ora"/></remark>
</para>
  </abstract>
  </articleinfo>
<section xmlns:xi="http://www.w3.org/2001/XInclude"><title>Pourquoi utiliser le réseau</title>
<para>Pourquoi ne peut-on pas de contenter d'applications locales ? Il
y a plusieurs raisons possibles.
  <itemizedlist>
	<listitem><para>
 C'est l'autre machine qui a les données
	</para></listitem>
	<listitem><para>
 C'est l'autre machine qui va vite
	</para></listitem>
	<listitem><para>C'est l'autre machine qui a les bons logiciels
	</para></listitem>
      </itemizedlist>
</para>

<para>Ce qui est sûr, c'est qu'on n'envisage plus de tout faire sur
une seule machine.</para>

<para>Un exemple courant est celui d'un <foreignphrase>middleware</foreignphrase> d'accès à une base de données : le <foreignphrase>middleware</foreignphrase>
permet de mettre les règles du métier (<foreignphrase>business logic</foreignphrase>) et de
pallier le manque de standardisation de SQL, ainsi que l'absence de
transport standard. Le fait
que le <foreignphrase>middleware</foreignphrase> soit client-serveur permet d'y accéder depuis
d'autres systèmes et d'autres langages de programmation (contrairement
aux bibliothèques, qui sont spécifiques d'un langage).</para>
  </section>
<section xmlns:xi="http://www.w3.org/2001/XInclude">
    <title>Avant les &ws;</title>
    <para>
Même si le marketing essaie de faire croire qu'avant les &ws; on
             vivait dans des cavernes, il y a longtemps que l'on fait de la programmation en réseau. Voyons
             quels étaient les techniques les plus utilisées.</para>
<section xmlns:xi="http://www.w3.org/2001/XInclude"><title>Bricolages divers</title>
<section xmlns:xi="http://www.w3.org/2001/XInclude"><title>Analyser HTML</title>
      <para>L'information est souvent disponible sur une page
             Web. L'analyse de telles pages Web est souvent présentée comme une solution
acceptable (&quot;Mais si, nos données sont accessibles en ligne&quot;).</para>
<para>Dans ce
             cas, on doit effectuer une requête HTTP et analyser
             l'HTML envoyé. Il existe de très bonnes bibliothèques
             pour ces opérations, dans tous les langages. Leurs
             auteurs ont du mérite, puisque
             pratiquement aucun
site n'envoie du HTML correct... Mais cela
             reste très pénible car HTML n'est pas utilisé comme
             langage de description de contenu mais comme langage de
             mise en page. L'information utile est donc noyée sous les
             informations de présentation.</para>
      <para>Pire, il est fréquent que cette présentation change subitement,
             cassant ainsi les analyseurs.<footnote><para>C'est
             couramment une action volontaire, le
             <foreignphrase>semantic firewall</foreignphrase>, pour
             empêcher les récupérations automatisées.</para>
	    </footnote>
</para>
<para>En outre, il est relativement rare que l'information soit
	  accessible directement à partir d'un URL, avec quelques
	  paramètres (par exemple 
	  <computeroutput>http://www.nic.fr/cgi-bin/whois?Object=$DOMAINE</computeroutput>).
	  Il faut souvent gérer une session, avec envoi de
	  <foreignphrase>cookies</foreignphrase> et manipulations
	  d'URL (ajout de <foreignphrase>session ID</foreignphrase>
	  qui empêchent la réutilisation de l'URL).</para>
<para>L'utilisation d'HTTP n'est pas limitée à la
consultation, elle permet aussi déclencher des actions par ce moyen, en appelant
avec la méthode POST.</para>
    </section>
    <section xmlns:xi="http://www.w3.org/2001/XInclude"><title>Analyser le non-formaté</title>
      <para>Dans d'autres cas, on doit transmettre en
             non-formaté et re-analyser derrière. C'est ce que fait
      whois/<xref linkend="RFC0954"/> : il formate de l'information en
texte, qu'on doit réanalyser après<footnote><para>Avec des
      bibliothèques compliquées comme <ulink url="http://open.gandi.net/">WhoisExtract</ulink> ou bien Net::XWhois.</para>
	  </footnote>, alors qu'elle
      était structurée dans une base de données ! Certains serveurs whois, heureusement,
      formatent l'information d'une manière un peu plus lisible, avec
      des doublets attributs-valeurs, par exemple :
<programlisting>
inetnum:      195.220.197.0 - 195.220.199.255
netname:      FR-UREC-HD
descr:        Reseau de l'Unite Reseaux du CNRS
country:      FR
admin-c:      JPG252-RIPE
tech-c:       BT261-RIPE
status:       ASSIGNED PA
mnt-by:       RENATER-MNT
changed:      rensvp@renater.fr 19990907
changed:      rensvp@renater.fr 20011031
source:       RIPE
</programlisting>
</para>
    </section>
    </section>
<section xmlns:xi="http://www.w3.org/2001/XInclude"><title>Solutions sérieuses</title>
<para>Contrairement à ce que prétendent certains vendeurs de &ws;, il
existait des solutions non bricolées.
<itemizedlist>
<listitem><para>On faisait tout à la main (définir un protocole, écrire les
clients et les serveurs)</para>
	    </listitem>
<listitem><para>On avait des solutions spécifiques à un langage (RMI)</para>
	    </listitem>
<listitem><para><link linkend="corba">Corba</link></para>
	    </listitem>
<listitem><para>ONC-RPC (SunRPC)</para>
	    </listitem>
	  </itemizedlist>
</para>
<para>La première approche est appréciée des techniciens, qui aiment
souvent réinventer la roue. Aujourd'hui, elle ne nécessite même plus
de tout refaire : <link linkend="beep">BEEP</link> simplifierait cette approche.

RMI est, lui, spécifique de Java (et .COM ou .NET de Microsoft). Cela
leur ôte tout intérêt puisque on utilise souvent les &ws; pour être
indépendant du langage de programmation.

Corba est trop lourd et compliqué et n'a eu aucun succès.

ONC-RPC (utilisé par exemple par NFS) était techniquement très douteux
(le portmapper...) mais a été largement déployé. Avec XDR, il formait
une solution acceptable à l'époque où il n'y avait pas le choix. Il a
popularisé le terme de RPC et, souvent, les idées de programmation distribuée.</para>

  </section>
    </section>
<section xmlns:xi="http://www.w3.org/2001/XInclude"><title>Les &ws; arrivent</title>

<para>Normalisés informellement ou bien par le <ulink url="http://www.w3.org/2002/ws/">W3C</ulink>, les &ws; représentent
l'approche à la mode aujourd'hui.</para>

<para>Ils s'appuient sur le succès du Web :
<itemizedlist>
<listitem><para>Disponibilité de HTTP,</para>
	  </listitem>
<listitem><para>Web, donc bon,</para>
	  </listitem>
<listitem><para>Et on passe les coupe-feux !</para>
	  </listitem>
	</itemizedlist>
</para>
<para>Le <xref linkend="RFC3205"/> présente un point de vue critique
qui sert de base à l'IETF pour un refus général des
&ws;<footnote><para>Les récents (RFC pas encore publié) protocoles comme EPP <foreignphrase>Extensible
Provisioning Protocol</foreignphrase> ou bien IRIS
<foreignphrase>Internet Registry Information Service</foreignphrase>
utilisent donc XML mais sans &ws;.</para>
      </footnote>. Mais cela
n'a pas empêché leur succès.</para>

<para>Qu'est-ce qui définit les &ws; ? Il n'y a pas de réponse simple,
même l'utilisation de XML ne suffit pas à les caractériser. Disons que
les &ws; comprennent :
<itemizedlist>
<listitem><para> Un encodage (toujours XML)</para>
	  </listitem>
<listitem><para>Un transport (souvent HTTP)</para>
	  </listitem>
<listitem><para>Une organisation des requêtes et réponses (RPC, par exemple)</para>
	  </listitem>
	</itemizedlist>
et s'appuient sur des technologies Web (serveur Apache, par exemple).
</para>

<para>Les &ws; sont généralement utilisés en mode RPC. RPC veut dire <foreignphrase>Remote Procedure Call</foreignphrase>. C'est le modèle le plus simple en programmation
distribuée. Tout est ramené à des appels de sous-programmes, avec des
paramètres entrants et un résultat.
</para>
<para>Les &ws; sont un mécanisme de communication <emphasis>entre
applications</emphasis>. Ils n'ont pas d'interface utilisateur. S'ils
sont souvent désignés par un URI, ils ne sont pas accessibles à un
navigateur Web classique. Un &uws; donné n'a d'intérêt que pour le
programmeur, son existence n'est pas connue de l'utilisateur final.</para>
    </section>

    <section xmlns:xi="http://www.w3.org/2001/XInclude"><title><link linkend="xml-rpc">XML-RPC</link>, le plus simple des &ws;</title>
<para>
Principe : la bibliothèque client encode les paramètres en XML et la
bibliothèque serveur les décode. Le programmeur ne voit <emphasis>jamais</emphasis> de XML.</para>

<para>On ne fait que des appels de procédure : un modèle simple et bien connu.</para>

<para>Le transport est normalisé pour HTTP seulement, bien que des
transports sur d'autres protocoles comme Jabber ou BEEP aient été mis
en oeuvre.</para>

<para>Il existe des bibliothèques pour tous : Perl, C, Python, Ruby, Java,
VisualBasic/.NET, PHP et même Emacs-Lisp.</para>

<formalpara><title>XML-RPC, exemple Java</title><para>
<programlisting>
 // The server has been created above
 Vector params = new Vector();
 params.addElement(new Integer(5));
 params.addElement(new Integer(3));
 // Call the server, and get our result.
 Hashtable result =
     (Hashtable) server.execute(&quot;sample.sumAndDifference&quot;, params);
 // We cannot use the procedure name directly (a limit of Java), hence
 // the &quot;execute&quot; method.
 int sum = ((Integer) result.get(&quot;sum&quot;)).intValue();
 int difference = ((Integer) result.get(&quot;difference&quot;)).intValue();
 // Java typing makes for convoluted expressions...
</programlisting></para>
</formalpara>

<formalpara><title>XML-RPC, exemple Python</title><para>
Le modèle de programmation de XML-RPC convient mieux aux langages
dynamiques et peu typés.
<programlisting>
 server = xmlrpclib.Server ('http://whois.eureg.org:8080/RPC2')
 # Call the server, and get our result.
 result = server.sample.sumAndDifference(3, 5);
 sum = result[&quot;sum&quot;]
 difference = result[&quot;difference&quot;]
</programlisting><function>sample.sumAndDifference</function> est une
 méthode. La notation pointée ne sert qu'à l'esthétique, XML-RPC ne
 connait pas de hiérarchie des méthodes.</para>
</formalpara>

<para>XML-RPC permet plusieurs types de paramètres :
<itemizedlist>
<listitem><para>entiers (comme l'exemple ci-dessus), dates, booléens, chaines de caractères</para>
	  </listitem>
<listitem><para><foreignphrase>structs</foreignphrase> (tableaux associatifs)</para>
	  </listitem>
<listitem><para>tableaux</para>
	  </listitem>
	</itemizedlist>
Dans les exemples ci-dessus, 
<function>sample.sumAndDifference</function> renvoyait une
<foreignphrase>struct</foreignphrase> de deux éléments.</para>

<para>Les erreurs sont signalées par des exceptions.</para>

<section xmlns:xi="http://www.w3.org/2001/XInclude"><title>XML-RPC, exemples de clients réels</title>
<section xmlns:xi="http://www.w3.org/2001/XInclude" id="meerkat"><title>Meerkat, un service d'informations en ligne</title>

<para><ulink url="http://www.oreillynet.com/pub/a/rss/2000/11/14/meerkat_xmlrpc.html">Meerkat</ulink> est
accessible en XML-RPC. Voici un exemple en PHP.</para>

<programlisting>
<![CDATA[
<?php
  $server_url = '/meerkat/xml-rpc/server.php';
  $msg = new xmlrpcmsg('meerkat.getCategories', array());
  $client = new xmlrpc_client($server_url, "www.oreillynet.com", 80);

  # Send our XML-RPC message to the server and receive a response in return
  $response = $client->send($msg);
  $value = $response->value();

  # And convert it to a PHP data structure
  $categories = xmlrpc_decode($value);

  # Iterate over the results, printing each category's title
  while( list($k, $v) = each( $categories ) ) {
    print $v['title'] . "<br />\n";
  }

?>

]]>
</programlisting>
      </section>

<section xmlns:xi="http://www.w3.org/2001/XInclude"><title>Adam's Names</title>

<para>Une interface d'accès au registre DNS, accessible <ulink url="http://www.adamsnames.tc/api/xmlrpc.html">en XML-RPC</ulink>.</para>

<para>Cela permet de développer un <application>whois</application>
moderne (ici en Perl), aux résultats analysables.
<programlisting>
   my $rpc = Frontier::Client-&gt;new( url =&gt; 
    'http://www.adamsnames.tc/api/xmlrpc' ); 
   my $status = $rpc-&gt;call('domquery', 'xmlrpcdemo.tc');
   my $dumper = Data::Dumper-&gt;new([ $status ])-&gt;Terse(1)-&gt;Indent(1);
   my $txt = $dumper-&gt;Dump;
</programlisting>
</para>
      </section>
      </section>

<section xmlns:xi="http://www.w3.org/2001/XInclude"><title>XML-RPC, le serveur</title>
<para>Ici, un extrait d'un serveur XML-RPC dans un registre DNS. Il
donne des informations sur un nom de domaine. Ce serveur utilise le
<foreignphrase>registry</foreignphrase> de XML-RPC (pour l'<link linkend="xml-rpc.introspection">introspection</link>).
<programlisting>
    self.registry.add_method('registry.queryDomain',
                                 self.domquery,
                                 [[STRUCT, STRING, STRUCT]])
    ...
    def domquery (self, domain, credentials):
        &quot;&quot;&quot;Queries the registry for a domain's attributes&quot;&quot;&quot;
        if credentials.has_key('name'):
            raise Unauthorized
        self.cursor.execute(&quot;&quot;&quot;
                SELECT name,
...
    def call (self, methodName, params):
        &quot;&quot;&quot;Use our registry to find and call the appropriate method.&quot;&quot;&quot;
        try:
            return self.registry.dispatch_call(methodName, params)
        except Unauthorized:
            raise xmlrpclib.Fault(403, 'Unauthorized')
</programlisting>

On enregistre la procédure <function>registry.queryDomain</function> :
elle prend une chaîne et une <foreignphrase>struct</foreignphrase> et
renvoie une  <foreignphrase>struct</foreignphrase>.</para>

<para><function>domquery</function> est une procédure normale, sans aucune connaissance de
XML-RPC (par exemple, elle lève des exceptions normales).</para>

<para><function>call</function> connait le protocole et lève donc des exceptions spécifiques.
</para>
      </section>

<section xmlns:xi="http://www.w3.org/2001/XInclude"><title>Divers</title>
<section xmlns:xi="http://www.w3.org/2001/XInclude"><title>XML-RPC, sur le câble</title>
<para>Cette section n'a d'importance pratique que si vous voulez écrire une
	(nouvelle) bibliothèque XML-RPC ou bien si vous observez une
	session avec <application>ethereal</application>. Le
	programmeur moyen ne voit pas l'encodage en XML.
<programlisting>
<![CDATA[
POST /RPC2 HTTP/1.0
User-Agent: Frontier/5.1.2 (NetBSD)
Host: betty.userland.com
Content-Type: text/xml
Content-length: 181

<?xml version="1.0"?>
<methodCall>
   <methodName>examples.getStateName</methodName>
   <params>
      <param>
         <value><i4>41</i4></value>
         </param>
      </params>
   </methodCall>
]]>
</programlisting>

Les en-têtes HTTP sont des en-têtes standard (<xref linkend="RFC2616"/>).
      </para>

      </section>
<section xmlns:xi="http://www.w3.org/2001/XInclude"><title>XML-RPC, limites</title>
	<itemizedlist>
	  <listitem><para>En standard, chaînes en ASCII
	  uniquement. Mais, en pratique, pas mal de mises en oeuvre de
	  XML-RPC <ulink url="http://www.xmlrpc.com/discuss/msgReader$2129?mode=day">ont Unicode</ulink>.</para>
	  </listitem>
	  <listitem><para>Pas normalisé sous un organisme neutre
	  (IETF, W3C, etc) ce qui est un handicap pour être utilisé
	  comme base pour d'autres protocoles normalisés.</para>
	  </listitem>
	</itemizedlist>
      </section>
    </section>
  </section>

<section xmlns:xi="http://www.w3.org/2001/XInclude"><title>SOAP, le plus vendu</title>

<para>
<link linkend="soap"><foreignphrase>Simple Object Access
Protocol</foreignphrase></link> est le protocole de &ws; le plus connu
aujourd'hui. Il dispose en effet du meilleur marketing (W3C et Microsoft).</para>

<para>SOAP est techniquement très proche de XML-RPC. La bibliothèque client encode les paramètres en XML et la
bibliothèque serveur les décode. Le programmeur ne voit <emphasis>jamais</emphasis> de XML.</para>

<para>On fait des appels de procédure, comme en XML-RPC, ou de l'asynchrone.</para>

<para>Il existe un grand choix de transports : en HTTP, BEEP, etc.</para>

<para>Le programmeur SOAP dispose d'un grand nombre de bibliothèques :
<link linkend="soap.lite">Perl</link>, C, C#, Python, Ruby, Java,
VisualBasic/.NET, PHP, Ada.</para>

<formalpara><title>SOAP, un exemple Perl</title>
<para>
<programlisting>
# Utilise l'AUTOLOAD de Perl
use SOAP::Lite +autodispatch =&gt;
    uri =&gt; 'http://www.soaplite.com/Temperatures',
    proxy =&gt; 'http://services.soaplite.com/temper.cgi';
print f2c(100), &quot;\n&quot;; # Appelle une procédure distante
</programlisting>
	<foreignphrase>uri</foreignphrase> identifie l'application
	(SOAP dit la classe et l'aiguillage vers la bonne classe se
	nomme <foreignphrase>dispatching</foreignphrase>)
	utilisée sur le serveur SOAP. Le même serveur peut héberger
	plusieurs applications. <foreignphrase>proxy</foreignphrase>
	identifie le serveur. Les deux sont des URI mais n'ont aucun
	rapport. Le premier est souvent un URN comme
	urn:GoogleSearch. Le second est plus physique : la machine
	nommée dans l'URL doit exister.</para>
      </formalpara>
<formalpara>
<title>SOAP, un exemple Python</title>
<para>On utilise <ulink url="http://pywebsvcs.sourceforge.net/">SOAPpy</ulink>.
<programlisting>
server = SOAP.SOAPProxy('http://api.google.com/search/beta2',
                        namespace='urn:GoogleSearch')
result = server.doGoogleSearch('Zls0Q7uAt2Lrcd7BHjai...zWJj7', 
                                  'python wsdl', ...);
print result['estimatedTotalResultsCount']
</programlisting>
La chaine incompréhensible est la clé de la licence Google.</para>
      </formalpara>

<section xmlns:xi="http://www.w3.org/2001/XInclude"><title>SOAP, détails</title>
<para>SOAP permet de nombreux types de paramètres :
<itemizedlist>
<listitem><para> entiers, dates, booléens, chaines, etc (tout ce qu'on peut
décrire avec les Schémas)</para>
	    </listitem>
<listitem><para><foreignphrase>structs</foreignphrase> (tableaux associatifs)</para>
	    </listitem>
<listitem><para>tableaux</para>
	      </listitem>
	  </itemizedlist>
</para>
<para>Les erreurs sont signalées par des exceptions
(<foreignphrase>faults</foreignphrase>).</para>
      </section>

<section xmlns:xi="http://www.w3.org/2001/XInclude"><title>SOAP, le serveur</title>
<para><programlisting>
use SOAP::Transport::HTTP;
my $daemon = SOAP::Transport::HTTP::Daemon
  -&gt; new (LocalAddr =&gt; 'localhost', LocalPort =&gt; 8080)
  -&gt; dispatch_to('Handler');
$daemon-&gt;handle;

package Handler;
sub hi {
    return &quot;hello, world&quot;;
}
sub bye {
    return &quot;goodbye, cruel world&quot;;
}
</programlisting>

Le serveur peut aussi être un CGI, un module mod_perl, etc.</para>
<para>Voici un serveur plus compliqué. Le code métier est dans un
	paquetage séparé. Le serveur peut recevoir des paramètres (ici
	$domain).
<programlisting>
# Le serveur proprement dit
use SOAP::Transport::HTTP;

my $daemon = SOAP::Transport::HTTP::Daemon
    -&gt; new (LocalAddr =&gt; 'soap.nic.fr', LocalPort =&gt; 8080)
    -&gt; dispatch_to(undef, Meticiel,
		   undef, undef);
print &quot;Contact to SOAP server at &quot;, $daemon-&gt;url, &quot;\n&quot;;
$daemon-&gt;handle;
	</programlisting>
<programlisting>
<![CDATA[
# Le code métier
package Meticiel;

sub is_available () {
    my ($class, $domain) = shift;
    $domain = lc($domain); 
    if ($domain !~ /\.fr$/) {
        return "We only register domains in \".fr\"";
    }
    if (&registered($domain)) {
        return "Domain $domain already registered";
    }
    return "Domain $domain is available. Buy it soon!";
}

sub registered () {
...
}

]]>
	</programlisting>
      </para>
<para>Un client pour ce serveur pourrait être :
<programlisting>
use SOAP::Lite;

$domain = shift(@ARGV);
if (! $domain) {
    die &quot;Usage: $0 domain-name&quot;;
}
print SOAP::Lite
    -&gt; uri('http://soap.nic.fr/Meticiel')
    -&gt; proxy('http://soap.nic.fr:8080/')
    -&gt; is_available($domain)
    -&gt; result;
print &quot;\n&quot;;
	</programlisting></para>
<para>Attention, la bibliothèque Perl SOAP::Lite ne lève pas
	d'exceptions (qui n'existent pas réellement en Perl bien qu'on
	puisse les simuler avec 
	<function>die</function>). Il vaudrait donc mieux tester le
	code de retour avant d'appeler <function>result</function> :
<programlisting>
unless ($result-&gt;fault) {
    print $result-&gt;result();
    print &quot;\n&quot;;
} else {
    print join ', ', 
    $result-&gt;faultcode, 
    $result-&gt;faultstring, 
    $result-&gt;faultdetail;
}
	</programlisting>. Vous pouvez aussi définir le traitant
	<function>on_fault</function> pour appeler
    <function>die</function> si vous préférez les exceptions.</para>
</section>

<section xmlns:xi="http://www.w3.org/2001/XInclude"><title>SOAP, sur le câble</title>
<para>Cela ne vous servira que si vous voulez écrire une bibliothèque.</para>

<para>SOAP s'appuie sur les schémas XML.

SOAP permet de transmettre du XML brut (à analyser soi-même).</para>

<programlisting>
<![CDATA[
POST /StockQuote HTTP/1.1
Content-Type: text/xml; charset="utf-8"
Content-Length: 2456
SOAPAction: "http://electrocommerce.org/abc#MyMessage"

<SOAP-ENV:Envelope
   xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
   SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
    <SOAP-ENV:Body>
        <myapp:GetLastTradePrice xmlns:myapp="Some-URI">
            <symbol>AFNIC</symbol>
        </myapp:GetLastTradePrice>
    </SOAP-ENV:Body>
 </SOAP-ENV:Envelope>

]]>
</programlisting>

<para>Les <foreignphrase>namespaces</foreignphrase> (ici, <systemitem>myapp</systemitem>) permettent de définir ses propres
élements, sans risque de collision.
</para>
	</section>

<section xmlns:xi="http://www.w3.org/2001/XInclude"><title>SOAP, les problèmes</title>
<para>
<itemizedlist>
<listitem><para>Usine à gaz</para>
	  </listitem>
<listitem><para>Peu interopérable</para>
	  </listitem>
	</itemizedlist>
</para>

<para><foreignphrase>What's wrong with SOAP?</foreignphrase> SOAP est
trop complexe, regardez la taille de sa spécification :

<programlisting>
wc soap-spec.txt
   1519   10671   79445 soap-spec.txt    
wc xmlrpc-spec.txt
    315    1657   15838 xmlrpc-spec.txt  
</programlisting>
</para>
    </section>
<section xmlns:xi="http://www.w3.org/2001/XInclude"><title>SOAP, exemples de clients réels</title>

<section xmlns:xi="http://www.w3.org/2001/XInclude"><title>Google</title>

<para>Google a un <ulink url="http://www.google.com/apis/index.html">accès SOAP</ulink>
décrit en WSDL
(inscription gratuite et obligatoire).</para>
      </section>

<section xmlns:xi="http://www.w3.org/2001/XInclude" id="amazon"><title>Amazon</title>

<para>Amazon a un <ulink url="http://www.amazon.com/webservices">accès
SOAP</ulink> (inscription obligatoire mais gratuite). Cela permet d'écrire des programmes pour retrouver des
informations au catalogue comme :
<programlisting>
% perl amazon-by-keyword.pl ipv6  
J. D. Wegner Robert Rockell Marc Blanchet Syngress Media 
IP Addressing and Subnetting, Including IPv6
$41.97

Joseph Davies 
Understanding IPv6
$20.99

Peter Loshin Pete Loshin 
IPv6 Clearly Explained
$46.95

Regis Desmeules 
Cisco Self-Study: Implementing Cisco IPv6 Networks (IPV6)
$55.00

...
</programlisting></para>
<para>L'API d'Amazon est assez complexe. Elle est entièrement
documentée dans le SDK (<foreignphrase>Software Development
Kit</foreignphrase>) téléchargeable sur le site d'Amazon et qui inclus
un fichier WSDL. Mais le programme Perl ci-dessus ne l'a pas utilisé, il se
contente du module Net::Amazon, disponible dans la CPAN :
<programlisting>
#!/usr/bin/perl

use Net::Amazon; # In CPAN

my $keywords = (shift(@ARGV) || die &quot;Usage: $0 keyword(s)&quot;);
my $ua = Net::Amazon-&gt;new(token =&gt; 'REGISTER_YOURSELF_DO_NOT_STEAL_MINE');
my $response = $ua-&gt;search(mode=&gt;&quot;books&quot;, keyword =&gt; $keywords);

if($response-&gt;is_success()) {
    foreach $property ($response-&gt;properties()) {
	%book = %{$property};
	foreach $author (@{$book{&quot;authors&quot;}}) {
	    print $author, &quot; &quot;;
	}
	print &quot;\n&quot;;
	print $book{&quot;title&quot;}, &quot;\n&quot;;
	print $book{&quot;OurPrice&quot;};
	print &quot;\n\n&quot;;
    }
} else {
    print &quot;Error: &quot;, $response-&gt;message(), &quot;\n&quot;;
}
</programlisting></para>
<para>Comme un paquetage analogue existe pour Python, ce programme
    pourrait s'écrire :
<programlisting>
#!/usr/bin/python

import amazon, sys # http://diveintomark.org/projects/
keyword = sys.argv[1]

books = amazon.searchByKeyword(keyword)
for book in books:
    print book.Authors.Author
    print book.ProductName # Title
    print book.OurPrice
    print 
</programlisting>
</para>
      </section>
    </section>
  </section>

<section xmlns:xi="http://www.w3.org/2001/XInclude"><title>UDDI, l'annuaire universel</title>
<para>UDDI a été normalisé par Oasis. Il permet d'enregistrer les Web Services, afin
de les retrouver (on l'a décrit comme <foreignphrase>The CPAN of Web Services</foreignphrase>).</para>

<para>UDDI comprend un protocole et plusieurs registres, peut-être
concurrents<footnote><para>Après le DNS et les certificats X509, voilà
encore du travail pour les gérants
de registre.</para>
      </footnote>.</para>

<para>Un registre UDDI peut être accédé en SOAP mais aussi en XML-RPC ou
Corba.</para>

<para>La documentation difficile à aborder (c'est Oasis...). L'information est très
structurée, avec beaucoup de niveaux (notez l'emboitement des
références dans l'exemple ci-dessous). Et la documentation n'est pas en hyper-texte :-(</para>

<formalpara><title>UDDI, exemple</title>
<para><programlisting>
use UDDI::Lite +autodispatch =&gt;
    proxy =&gt; 'http://uddi.microsoft.com/inquire';

$info = find_business(name =&gt; 'amazon')
    -&gt; businessInfos-&gt;businessInfo-&gt;serviceInfos-&gt;serviceInfo;
print $info-&gt;name, &quot;\n&quot;;
</programlisting></para>
    </formalpara>

<formalpara><title>UDDI, les détails</title>
<para><programlisting>
# find_* : &quot;fuzzy&quot; searches
# get_*  : exact searches, with the key
$mybusinessList = find_business(name =&gt; 'ama');
$mybusinessInfos = $mybusinessList-&gt;businessInfos;
@mybusinessInfo = $mybusinessInfos-&gt;businessInfo;
for $mybusinessInfo  (@mybusinessInfo) {

    print $mybusinessInfo-&gt;name, &quot;\n&quot;;
    print $mybusinessInfo-&gt;businessKey, &quot;\n\n&quot;;

    $myserviceInfos = $mybusinessInfo-&gt;serviceInfos;
    @myserviceInfo = $myserviceInfos-&gt;serviceInfo;
    
    for $myserviceInfo  (@myserviceInfo) {
	print &quot;   &quot;, $myserviceInfo-&gt;name, &quot;\n&quot;;
	print &quot;   &quot;, $myserviceInfo-&gt;serviceKey, &quot;\n&quot;;
	@myserviceDetails = get_serviceDetail
	    (serviceKey =&gt; $myserviceInfo-&gt;serviceKey);
	for $myserviceDetail  (@myserviceDetails) {
	    print &quot;      &quot;, $myserviceDetail-&gt;name, &quot;\n&quot;;
	    print &quot;      &quot;, $myserviceDetail-&gt;description, &quot;\n&quot;;
	    $mybindingTemplate = $myserviceDetail-&gt;bindingTemplates-&gt;bindingTemplate; # Actually, several
	    print &quot;         &quot;, $mybindingTemplate-&gt;description, &quot;\n&quot;;
	    print &quot;         &quot;, $mybindingTemplate-&gt;accessPoint, &quot;\n&quot;;
	}
	print &quot;\n&quot;;
    }
    
    print &quot;\n\n&quot;;
}
</programlisting>
</para>
    </formalpara>

    </section>

<section xmlns:xi="http://www.w3.org/2001/XInclude" id="wsdl"><title>WSDL, méta-informations</title>
<para>WSDL est un langage du W3C pour décrire les API
(<foreignphrase>Application Programming Interface</foreignphrase>) des
&ws; (surtout pour SOAP). Il est décrit en XML.</para>
<para>WSDL est complexe car il permet de décrire plusieurs modèles
d'interactions, pas seulement le classique RPC. Comme il s'appuie sur
les schémas XML (notamment pour les types de données), il faut
connaitre les schémas d'abord.</para>
<para>WSDL peut servir de documentation formelle à vos &ws;,
documentation que vous pouvez ensuite présenter joliment grâce à des
<ulink url="http://www.capescience.com/articles/simplifiedWSDL/">feuilles de
style</ulink> mais on peut aussi écrire des clients qui analysent le
WSDL et trouvent ainsi &quot;tout seul&quot; la marche à suivre pour utiliser le &uws;.</para>
<formalpara><title>WSDL, un extrait</title>
<para><programlisting>
<![CDATA[
      <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:complexType>
...
  <message name="doGoogleSearch">
    <part name="key"            type="xsd:string"/>
    <part name="q"              type="xsd:string"/>
...
  </message>

  <message name="doGoogleSearchResponse">
    <part name="return"         type="typens:GoogleSearchResult"/>           
  </message>

]]>
</programlisting>
</para>
    </formalpara>

<formalpara><title>WSDL, exemple d'utilisation</title>
<para><programlisting>
my $google = SOAP::Lite-&gt;service('http://api.google.com/GoogleSearch.wsdl');
my $result = $google-&gt;doGoogleSearch(
  $key, $query, 0, 10, 'false', '', 'false', '', 'latin1', 'latin1');
</programlisting>
Ici, le client Perl a trouvé le type des paramètres uniquement en
utilisant le fichier <filename>GoogleSearch.wsdl</filename>.</para>
    </formalpara>
  </section>

<section xmlns:xi="http://www.w3.org/2001/XInclude"><title>Utiliser un &uws;, quelques conseils</title>
<para>Pour mettre en harmonie tous les concepts vus jusqu'à présent,
essayons l'utilisation d'un &uws; réel. Beaucoup de
<foreignphrase>feeds</foreignphrase> de nouvelles sont disponibles sur
Internet, utilisant en général l'une des variantes du langage <ulink url="http://www.xml.com/pub/a/2002/12/18/dive-into-xml.html">RSS</ulink>
(<link linkend="meerkat">Meerkat</link> en fait partie).
La difficulté est de trouver le bon
<foreignphrase>feed</foreignphrase>. Certains offrent des services de
recherche de <foreignphrase>feed</foreignphrase> et <ulink url="http://www.syndic8.com/">Syndic8</ulink>, que nous
utilisons ici, offre une interface &ws;, ici XML-RPC.</para>
<para>Avant toute utilisation d'un &ws; il faut évidemment avoir
appris à écrire un client, même trivial, dans son langage de
programmation favori, et il faut avoir donc choisi une bibliothèque
(par exemple, en Perl, il existe trois bibliothèques pour faire du
XML-RPC).</para>
<para>Ensuite, la première étape est de lire la spécification du
service. (Cette étape peut être partiellement sautée si le service est
décrit en <link linkend="wsdl">WSDL</link>.) Sinon, la spécification
est en général une page Web comme <ulink url="http://www.syndic8.com/services.php">celle de
Syndic8</ulink>. Pour notre service convoité, on apprend que Syndic8
permet de trouver les <foreignphrase>feeds</foreignphrase> en
indiquant un motif (comme &quot;Internet&quot; ou bien &quot;France&quot;), c'est le
service <function>syndic8.FindFeeds</function> et donne des
informations détaillées sur les <foreignphrase>feeds</foreignphrase>
si on lui fournit l'index (<foreignphrase>ID</foreignphrase>) de
ceux-ci, c'est le service
<function>syndic8.GetFeedInfo</function>.</para>
<para>On trouve également dans la documentation l'URL
(<foreignphrase>end point</foreignphrase>) du service, ici <function>http://www.syndic8.com/xmlrpc.php</function>.</para>
<para>On peut alors écrire un programme, ici en Python :
<programlisting>
#!/usr/bin/python

import xmlrpclib, socket

server = &quot;http://www.syndic8.com/xmlrpc.php&quot;
pattern = &quot;france&quot;
try:
    handle = xmlrpclib.Server (server)
    feeds = handle.syndic8.FindFeeds(pattern)
    for feed in feeds:
        info = handle.syndic8.GetFeedInfo (feed)
        print &quot;Feed %s:&quot; % feed
        print info
except socket.error, message:
    print &quot;Cannot contact the server: &quot; + str(message)
except xmlrpclib.ProtocolError, message:
    print &quot;The server refused to reply: &quot; + str(message)
except xmlrpclib.Fault, message:
    print &quot;Error/bug inside the server: &quot; + str(message)
    </programlisting>
</para>
<para>Ce premier programme a plusieurs limites : 
  <orderedlist>
	<listitem><para>Il imprime tout le résultat de
	<function>syndic8.GetFeedInfo</function>, un
	<foreignphrase>struct</foreignphrase>, alors que tous les
	champs ne sont pas utiles. On note que les champs
	de ce tableau associatif ne sont pas documentés, hélas, mais
	leur nom est en général clair.</para>
	</listitem>
	<listitem><para>Il imprime tous les
	<foreignphrase>feeds</foreignphrase> correspondant à notre
	motif &quot;France&quot; alors que, dans ce genre de services, la
	majorité des <foreignphrase>feeds</foreignphrase> indiqués sont
	hors service. Syndic8 les détecte et met un statut utile dans
	la <foreignphrase>struct</foreignphrase>.</para>
	</listitem>
	<listitem><para>Les champs de texte sont en <ulink url="http://www.unicode.org/">Unicode</ulink> ce qui est
      habituel dans le monde XML mais Python ne traite pas l'Unicode
      par défaut.</para>
	</listitem>
      </orderedlist></para>
<para>Voici une nouvelle version, qui n'imprime les
<foreignphrase>feeds</foreignphrase>  que si leur statut est positif
et qu'ils portent suffisamment d'articles. D'autre part, on n'imprime
plus tous les champs mais seulement la description et l'URL où on
pourra récupérer l'élement RSS. Enfin, on gère correctement l'Unicode.
<programlisting>
#!/usr/bin/python

import xmlrpclib, socket

server = &quot;http://www.syndic8.com/xmlrpc.php&quot;
pattern = &quot;france&quot;
try:
    handle = xmlrpclib.Server (server, verbose=0)
    feeds = handle.syndic8.FindFeeds(pattern)
    for feed in feeds:
        info = handle.syndic8.GetFeedInfo (feed)
        if info[&quot;status&quot;] == &quot;Syndicated&quot; and \
           float(info[&quot;headlines_per_day&quot;]) &gt; 5: # Only keep those that are active
            print &quot;Feed %s:&quot; % feed
            desc = unicode (info[&quot;description&quot;]) # Turn it into an
                                                 #  Unicode string.
            print desc.encode (&quot;latin-1&quot;),       # Print what my
                                                 #  terminal supports, here Latin-1.
            print &quot; (&quot; + info[&quot;dataurl&quot;] + &quot;)&quot;
except socket.error, message:
    print &quot;Cannot contact the server: &quot; + str(message)
except xmlrpclib.ProtocolError, message:
    print &quot;The server refused to reply: &quot; + str(message)
except xmlrpclib.Fault, message:
    print &quot;Error/bug inside the server: &quot; + str(message)
</programlisting></para>
<para>Ce programme peut alors afficher :
<programlisting>
Feed 369:
France News  (http://p.moreover.com/cgi-local/page?index_france+rss)
</programlisting>
</para>
</section>

<section xmlns:xi="http://www.w3.org/2001/XInclude"><title>Déployer un &uws;, quelques conseils</title>
<para>Avant de déployer un &uws; quelques points sont à considérer. La
plupart relèvent du bon sens mais il est prudent des les mentionner explicitement.</para>
<section xmlns:xi="http://www.w3.org/2001/XInclude"><title>Spécifier le service</title>
<para>Cela implique une réflexion sur l'API qui sera présentée aux
utilisateurs. Comme changer l'API nécessiterait un changement de tous
les clients, il faut tenter de réussir l'API du premier coup,
probablement en testant ses versions béta avec de vrais
utilisateurs.</para>
<para>Il faudra aussi choisir un protocole, XML-RPC ou bien SOAP.</para>
    </section>
<section xmlns:xi="http://www.w3.org/2001/XInclude"><title>Sécurité</title>
<para>Un &uws; n'est pas forcément accessible depuis l'extérieur de
votre organisation. Mais, s'il l'est, la sécurité est
essentielle. S'il fonctionne qu'en lecture seule, n'agissant en rien sur
vos données, il pourra être anonyme. S'il modifie vos données, il
faudra un mécanisme d'authentification, soit bâti dans votre
application, soit récupéré dans l'environnement extérieur (Apache, par
exemple, si vous utilisez SOAP en CGI ou en module Apache).</para>
<para>On pourra consulter <ulink url="http://www.schneier.com/crypto-gram-0006.html#SOAP">l'article sur
SOAP dans Cryptogram</ulink>.</para>
  </section>
<section xmlns:xi="http://www.w3.org/2001/XInclude"><title>Composants métier</title>
<para>Naturellement, le but du &uws; est de donner accès à des
applications spécifiques de votre métier. Ces applications ont souvent
été écrites avant le &uws;. Si elles sont sous forme de bibliothèques
bien écrites (API claire, pas d'effets de bord), elles pourront être
appelées directement par le &uws;.</para>
    </section>
  </section>

  <section xmlns:xi="http://www.w3.org/2001/XInclude">
    <title>Vers une généralisation des &ws; ?</title>
    <para>&uws; est désormais un terme à la mode : il apparait dans
    tous les nouveaux projets informatiques, des livres lui sont
    consacrés<footnote><para>739 à Amazon aujourd'hui.</para>
      </footnote>. Comme tous les termes à la mode, l'abondance de
    références n'a d'égale que le petit nombre de projets
    effectivement déployés. Encore que ce nombre n'est pas facile à
    mesurer, une grande partie des déploiements étant uniquement faits
    en interne.</para>
    <para>Y aura t-il un jour déploiement massif des &ws; ? La réponse
    n'est pas simple car elle dépend de deux choses :
<orderedlist><listitem><para>La migration des services réseaux depuis
    Corba, ONC-RPC ou depuis les protocoles privés, vers les
    techniques XML. C'est une décision surtout technique et les &ws;
    ont de bons arguments ici.</para>
	</listitem>
<listitem><para>L'exposition par les organisations de leur Système
	    d'Information interne, sous forme de &ws; accessibles
	    depuis l'extérieur.</para>
<para>Et, là, c'est beaucoup plus incertain : cela nécessiterait de
	    surmonter de nombreux blocages non techniques, notamment
	    la culture de la rétention d'information. Les techniques
	    existantes, peu pratiques, ont justement cet avantage pour
	    beaucoup de décideurs : elles rendent l'accès à
	    l'information plus difficile. <xref linkend="cio.battle"/>
	    expose une partie des problèmes qui se posent.</para>
	</listitem>
      </orderedlist></para>
  </section>

<bibliography><biblioentry id="beep">
    <author><surname>beepcore.org</surname>
    
    </author>
    
    
  
   <title>BEEP Home Page</title>
    
  
   <date>?</date>
    
    
  
    <abstract><para><ulink url="http://www.beepcore.org/">http://www.beepcore.org/</ulink>
    
    </para>
    
    </abstract>
    
    
  
  </biblioentry>
    <biblioentry id="beep.rose">
    <author><firstname>Marshall</firstname>
    
    <othername>T.</othername>
    
    <surname>Rose</surname>
    
    </author>
    
    
  
    <title>BEEP: The Definitive Guide </title>
    
  
    <date>2002</date>
    
    
  
    
  
    
  
    <publisher><publishername>O'Reilly</publishername>
    
    </publisher>
    
    
  
  </biblioentry>
    <biblioentry id="corba">
    <author><surname>Object Management Group</surname>
    
    </author>
    
    
  
    <title>Corba Home Page</title>
    
  
    <date>?</date>
    
    
  
    <abstract><para><ulink url="http://www.corba.org/">http://www.corba.org/</ulink>
    
    </para>
    
    </abstract>
    
    
  
  </biblioentry>
    <biblioentry id="cio.battle">
    <author><firstname>Christopher</firstname>
    
    <surname>Koch</surname>
    
    </author>
    
    
  
    <title>The battle for Web Services</title>
    
  
    <date>2003</date>
    
    
  
    <abstract><para><ulink url="http://www.cio.com/archive/100103/standards.html">http://www.cio.com/archive/100103/standards.html</ulink>
    
    </para>
    
    </abstract>
    
    
  
  </biblioentry>
    <biblioentry id="xml-rpc">
    <author><surname>UserLand Software</surname>
    
    </author>
    
    
  
    <title>XML-RPC Home Page</title>
    
  
    <date>2003</date>
    
    
  
    <abstract><para><ulink url="http://www.xml-rpc.com/">http://www.xml-rpc.com/</ulink>
    
    </para>
    
    </abstract>
    
    
  
  </biblioentry>
    <biblioentry id="xml-rpc.introspection">
    <author><firstname>Eric</firstname>
    
    <surname>Kidd</surname>
    
    </author>
    
    
  
    <title>XML-RPC introspection protocol</title>
    
  
    <date>2001</date>
    
    
  
    <abstract><para><ulink url="http://xmlrpc-c.sourceforge.net/xmlrpc-howto/xmlrpc-howto-api-introspection.html">http://xmlrpc-c.sourceforge.net/xmlrpc-howto/xmlrpc-howto-api-introspection.html</ulink>
    
    </para>
    
    </abstract>
    
    
  
  </biblioentry>
    <biblioentry id="xml-rpc.ora">
    <author><firstname>Simon</firstname>
    
    <othername>St.</othername>
    
    <surname>Laurent</surname>
    
    </author>
    
    
  
    <author><firstname>Joe</firstname>
    
    <surname>Johnston</surname>
    
    </author>
    
    
  
    <author><firstname>Edd</firstname>
    
    <surname>Dumbill</surname>
    
    </author>
    
    
  
    <title>Programming Web Services with XML-RPC</title>
    
  
    <date>2001</date>
    
    
  
    
  
    
  
    
  
    <publisher><publishername>O'Reilly</publishername>
    
    </publisher>
    
    
  
  </biblioentry>
    <biblioentry id="soap">
    <author><surname>Userland Software</surname>
    
    </author>
    
    
  
    <title>SOAP Home Page</title>
    
  
    <date>2003</date>
    
    
  
    <abstract><para><ulink url="http://www.soapware.org/">http://www.soapware.org/</ulink>
    
    </para>
    
    </abstract>
    
    
  
  </biblioentry>
    <biblioentry id="soap.lite">
    <author><firstname>Paul</firstname>
    
    <surname>Kulchenko</surname>
    
    </author>
    
    
  
    <title>SOAP::Lite for Perl</title>
    
  
    <date>2003</date>
    
    
  
    <abstract><para><ulink url="http://www.soaplite.com/">http://www.soaplite.com/</ulink>
    
    </para>
    
    </abstract>
    
    
  
  </biblioentry>
    <biblioentry id="soap.ora"> 
    <author><firstname>James</firstname>
    
    <surname>Snell</surname>
    
    </author>
    
    
  
    <author><firstname>Doug</firstname>
    
    <surname>Tidwell</surname>
    
    </author>
    
    
  
    <author><firstname>pavel</firstname>
    
    <surname>Kulchenko</surname>
    
    </author>
    
    
  
    <title>Programming Web Services with SOAP</title>
    
  
    <date>2001</date>
    
    
  
    
  
    
  
    
  
    <publisher><publishername>O'Reilly</publishername>
    
    </publisher>
    
    
  
  </biblioentry>
    <biblioentry id="RFC0954"><author><firstname>K.</firstname>
    
    <surname>Harrenstien</surname>
    
    </author>
    
    
      <author><firstname>M.</firstname>
    
    <surname>Stahl</surname>
    
    </author>
    
    
      <author><firstname>E.</firstname>
    
    <surname>Feinler</surname>
    
    </author>
    
    
      
<title>RFC 0954: NICNAME/WHOIS</title>
    
      
<date>1985</date>
    
    
      
      
</biblioentry>
    <biblioentry id="RFC2616"><author><firstname>R.</firstname>
    
    <surname>Fielding</surname>
    
    </author>
    
    
      <author><firstname>J.</firstname>
    
    <surname>Gettys</surname>
    
    </author>
    
    
      <author><firstname>J.</firstname>
    
    <surname>Mogul</surname>
    
    </author>
    
    
      <author><firstname>H.</firstname>
    
    <surname>Frystyk</surname>
    
    </author>
    
    
      <author><firstname>L.</firstname>
    
    <surname>Masinter</surname>
    
    </author>
    
    
      <author><firstname>P.</firstname>
    
    <surname>Leach</surname>
    
    </author>
    
    
      <author><firstname>T.</firstname>
    
    <surname>Berners-Lee</surname>
    
    </author>
    
    
      
<title>RFC 2616: Hypertext Transfer Protocol -- HTTP/1.1</title>
    
      
<date>1999</date>
    
    
      
      
</biblioentry>
    <biblioentry id="RFC3205"><author><firstname>K.</firstname>
    
    <surname>Moore</surname>
    
    </author>
    
    
      
<title>RFC 3205: On the use of HTTP as a Substrate</title>
    
      
<date>2002</date>
    
    
      
      
</biblioentry>
    </bibliography>
</article>
