IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Développons en Java v 2.20   Copyright (C) 1999-2021 Jean-Michel DOUDOUX.   
[ Précédent ] [ Sommaire ] [ Suivant ] [ Télécharger ]      [ Accueil ] [ Commentez ]


 

69. Les services web de type Soap

 

chapitre 6 9

 

 

Niveau : niveau 5 Confirmé 

 

Les services web de type Soap permettent l'appel d'une méthode d'un objet distant en utilisant un protocole web pour le transport (http en général) et XML pour formater les échanges. Les services web fonctionnent sur le principe client / serveur :

  • un client appelle les services web
  • le serveur traite la demande et renvoie le résultat au client
  • le client utilise le résultat

L'appel de méthodes distantes n'est pas une nouveauté mais la grande force des services web est d'utiliser des standards ouverts et reconnus notamment HTTP et XML. L'utilisation de ces standards permet d'écrire des services web dans plusieurs langages et de les utiliser sur des systèmes d'exploitation différents.

Les services web de type Soap utilisent des messages au format XML pour permettre l'appel de méthodes ou l'échange de messages.

Certaines fonctionnalités complémentaires mais généralement utiles des services web ne sont pas encore complètement matures à cause de la jeunesse des technologies utilisées pour les mettre en oeuvre. Il reste encore de nombreux domaines à enrichir (sécurité, gestion des transactions, workflow, ... ). Des technologies pour répondre à ces besoins sont en cours de développement mais généralement plusieurs solutions sont en concurrence.

Initialement, Sun a proposé un ensemble d'outils et d'API pour permettre le développement de services web avec Java. Cet ensemble se nomme JWSDP (Java Web Services Developer Pack) dont il existe plusieurs versions.

Depuis, Sun a intégré la plupart de ces API permettant le développement de services web dans les spécifications de J2EE version 1.4.

La version 5 de Java EE et la version 6 de Java SE utilisent JAX-WS 2.0 pour faciliter le développement de services web en utilisant des annotations.

Ce chapitre contient plusieurs sections :

 

69.1. La présentation des services web

Les services web sont des composants distribués qui offrent des fonctionnalités aux applications au travers du réseau en utilisant des standards ouverts. Ils peuvent donc être utilisés par des applications écrites dans différents langages et exécutées dans différentes plate-formes sur différents systèmes.

Les services Web utilisent une architecture distribuée composée de plusieurs ordinateurs et/ou systèmes différents qui communiquent sur le réseau. Ils mettent en oeuvre un ensemble de normes et standards ouverts qui permettent aux développeurs d'implémenter des applications distribuées internes ou externes en utilisant des outils différents fournis par les fournisseurs.

Un service web permet généralement de proposer une ou plusieurs fonctionnalités métiers qui seront invoquées par un ou plusieurs consommateurs.

Il existe deux grandes familles de services web :

  • les services web de type SOAP
  • les services web de type REST

Ce chapitre va se concentrer sur les services web de type SOAP.

 

69.1.1. La définition d'un service web

Il existe plusieurs définitions pour les services web mais la plus simple pourrait être "fonctionnalité utilisable au travers du réseau en mettant en oeuvre un format standard utilisant généralement XML".

Les services web ne sont donc qu'une nouvelle forme d'échanges de type RPC (Remote Procedure Call). Leur grand intérêt est de reposer sur des standards plutôt que sur des protocoles propriétaires. Par exemple, le transport repose généralement sur le protocol HTTP mais il est possible d'utiliser d'autres protocoles tels que JMS, FTP ou SMTP.

Les services web de type Soap font un usage intensif de XML, des namespaces XML et des schémas XML. Ces technologies font la force des services web pour permettre leur utilisation par des clients et des serveurs hétérogènes. XML est notamment utilisé pour stocker et organiser les informations de la requête et de la réponse mais aussi pour décrire le service web. L'utilisation de XML pour le format des messages rend les échanges indépendants du système d'exploitation, de la plate-forme et du langage.

Il est ainsi possible de développer des services web avec une plate-forme (par exemple Java) et d'utiliser ces services web avec une autre plate-forme (par exemple .Net ou PHP) : c'est une des grandes forces des services web même si cela reste parfois quelque peu théorique, essentiellement à cause des implémentations des moteurs utilisés pour mettre en oeuvre les services web.

Un service web est donc une fonctionnalité accessible au travers du réseau grâce à des messages au format XML. Le format de ces messages est généralement SOAP bien que d'autres formats existent (REST, XML-RPC, ...).

Les services web peuvent prendre plusieurs formes :

  • métier
  • technique
  • ...

Lors de la mise en place de services web, plusieurs problématiques interviennent tôt ou tard :

  • choix des spécifications mises en oeuvre
  • choix des outils
  • traitements proposés par les services
  • administration des services
  • orchestration des services
  • ...

L'appel à un service web de type SOAP suit plusieurs étapes :

  1. le client instancie une classe de type proxy encapsulant le service Web XML.
  2. le client invoque une méthode du proxy.
  3. le moteur SOAP sur le client crée le message à partir des paramètres utilisés pour invoquer la méthode
  4. le moteur SOAP envoie le message SOAP au serveur généralement en utilisant le protocol HTTP
  5. le moteur SOAP du serveur réceptionne et analyse le message SOAP
  6. le moteur fait appel à la méthode de l'objet correspondant à la requête SOAP
  7. le moteur SOAP sur le serveur crée le message réponse à partir de la valeur de retour
  8. le moteur SOAP envoie le message SOAP contenant la réponse au client généralement en utilisant le protocole http
  9. le moteur SOAP du client réceptionne et analyse le message SOAP
  10. le moteur SOAP du client instancie un objet à partir du message SOAP contenant la réponse

Un des intérêts des services web est de masquer aux développeurs la complexité de l'utilisation des standards sous-jacents. Ceci est réalisé grâce aux développements d'API et de moteurs pour la production et la consommation de services web.

Ces API sont dépendantes des plate-formes utilisées (Java, .Net, PHP, Perl, ...) mais elles mettent toutes en oeuvre avec plus ou moins de complétude les standards de l'industrie relatifs aux services web notamment SOAP et WSDL.

Ainsi les développeurs peuvent se concentrer sur l'écriture des traitements proposés par les services et par leur consommation sans se soucier de la tuyauterie sous-jacente. Un minimum de compréhension est cependant nécessaire pour bien appréhender les mécanismes mis en oeuvre.

 

69.1.2. Les différentes utilisations

Les services web proposent un mécanisme facilitant :

  • la communication entre applications hétérogènes : un service web développé dans une technologie peut être consommé par une application développée dans une autre technologie. Ceci est possible car les services web reposent sur des standards ouverts
  • l'exposition de fonctionnalités métiers aux applications internes mais aussi à des applications externes : dans ce dernier cas l'utilisation du protocole HTTP permet facilement de passer les pare-feux
  • la mise en oeuvre d'une architecture SOA puisque les services web peuvent être une implémentation possible d'une telle architecture

L'utilisation de services web peut avoir plusieurs intérêts :

  • l'exposition de fonctionnalités au travers du réseau : les traitements des opérations des services web peuvent être invoqués par une requête HTTP, ce qui peut permettre à plusieurs applications de consommer ces services web
  • la communication entre des applications et des systèmes hétérogènes : l'utilisation de standards ouverts permet la production et la consommation des services web par différentes technologies sur différents systèmes d'exploitation
  • la mise en oeuvre des protocoles standards de l'industrie au niveau des couches transport, messaging, description et recherche permet de choisir entre plusieurs implémentations proposées et ainsi de ne pas dépendre d'un seul fournisseur
  • les échanges se font en utilisant l'infrastructure existante puisque les services web sont généralement invoqués en utilisant le protocole HTTP. Ceci permet de facilement passer un firewall pour permettre une invocation depuis l'extérieur
  • les services web permettent un couplage faible entre les fonctionnalités exposées et les applications qui les utilisent à tel point que les consommateurs et les producteurs peuvent être écrits pour des plate-formes ou des langages différents (Java, .Net, PHP, ...).
  • les services permettent de définir de nouvelles opportunités de business voire même de nouveaux modèles économiques en permettant de proposer des fonctionnalités à des partenaires par exemple

 

69.2. Les standards

L'intérêt des services web grandissant, des standards ont été développés pour assurer les besoins nécessaires à leur mise en oeuvre.

L'architecture des services web est composée de quatre grandes couches utilisant plusieurs technologies :

  • découverte : cette couche représente un annuaire dans lequel il est possible de publier des services et de les rechercher (UDDI est le standard)
  • description : cette couche normalise la description de l'interface publique d'un service web en utilisant WSDL (Web Service Description Language)
  • communication : cette couche permet d'encoder les messages échangés (SOAP est le standard)
  • transport : cette couche assure le transport des messages : généralement HTTP est mis en oeuvre mais d'autres protocoles peuvent être utilisés (SMTP, FTP, ...)

La description d'un service web permet à son consommateur de connaître l'interface du service.

La communication permet de formaliser le format des messages échangés.

En plus de SOAP, WSDL et UDDI, il existe de nombreuses autres spécifications plus ou moins standard pour permettre la mise en oeuvre de fonctionnalités manquantes dans ces standards comme la sécurité, la gestion des transactions, l'orchestration des services, ...

Ces spécifications sont en cours de développement ou d'évolution ce qui les rend généralement immatures. De plus, fréquemment, il existe plusieurs spécifications ayant trait à un même sujet qui sont donc concurrentes. La mise en oeuvre de ces spécifications n'est pas requise pour des services web basiques mais elle peut être nécessaire pour des besoins plus spécifiques.

 

69.2.1. SOAP

SOAP (acronyme de Simple Object Acces Protocol jusqu'à sa version 1.1) est un standard du W3C qui permet l'échange formaté d'informations entre un client et un serveur. SOAP peut être utilisé pour la requête et la réponse de cet échange.

SOAP assure la partie messaging dans l'architecture des services web : il est utilisé pour normaliser le format des messages échangés entre le consommateur et le fournisseur de services web. SOAP est donc un protocole qui est principalement utilisé pour dialoguer avec des objets distribués comme peut le proposer JRMP utilisé par RMI, DCOM ou IIOP.

Son grand intérêt est d'utiliser XML ce qui le rend ouvert contrairement aux autres protocoles qui sont propriétaires : cela permet la communication entre un client et un serveur utilisant des technologies différentes. SOAP fait un usage intensif des espaces de nommages (namespaces).

SOAP est défini pour être indépendant du protocole de transport utilisé pour véhiculer le message. Cependant, le protocole le plus utilisé avec SOAP est HTTP car c'est un des protocoles le plus répandu et utilisé du fait de sa simplicité. Son utilisation avec SOAP permet de rendre les services web plus interopérables. De plus, cela permet aux services web de facilement traverser les firewalls du côté producteur et consommateur notamment dans le cas d'échanges par internet.

D'autres protocoles peuvent être utilisés (par exemple SMTP ou FTP) mais leur configuration sera plus délicate car elle ne sera pas fournie en standard comme c'est le cas avec HTTP. En fait, tous les protocoles capables de véhiculer un flux d'octets peuvent être utilisés.

SOAP est aussi indépendant de tout système d'exploitation et de tout langage de programmation car il utilise XML. Ceci permet une exposition et une consommation de services web avec des outils et des OS différents.

SOAP peut être utilisé pour :

  • appeler une méthode d'un service (SOAP RPC)
  • echanger un message avec un service (SOAP Messaging)
  • recevoir un message d'un service (selon la version de Soap)

 

69.2.1.1. La structure des messages SOAP

Un message SOAP est contenu dans une enveloppe, ainsi le tag racine d'un document SOAP est le tag <Envelope>.

La structure d'une enveloppe SOAP se compose de plusieurs parties :

  • un en-tête optionnel composé d'un ou plusieurs headers : il contient des informations sur le traitement du message
  • un corps (Body) : il contient les informations de la requête ou de la réponse
  • une gestion d'erreurs optionnelle (Fault) contenue dans le corps
  • des pièces jointes optionnelles (attachment) contenues dans le corps

L'en-tête contient des informations sur le traitement du message : ces informations sont contenues dans un tag <Header>. Pour des services web simples, cette partie peut être vide ou absente mais pour des services plus complexes elle peut contenir des informations concernant les transactions, la sécurité, le routage, etc ...

Le corps du message SOAP est contenu dans un tag <Body> obligatoire. Il contient les données échangées entre le client et le service sous la forme d'un fragment de document XML.

Tous ces éléments sont codés dans le message XML avec un tag particulier mettant en oeuvre un espace de nommage particulier défini dans les spécifications de SOAP.

Un message SOAP peut aussi contenir des pièces jointes placées chacune dans une partie optionnelle nommée AttachmentPart. Ces parties appartiennent à la partie SOAP Part.

SOAP définit aussi l'encodage pour les différents types de données qui est basé sur la technologie schéma XML du W3C. Les données peuvent être de type simple (chaine, entier, flottant, ...) ou de type composé.

Les types simples peuvent être

  • un type de base : string, int, float, ...
  • une énumération
  • un tableau d'octets (array of bytes)

Les types composés

  • une structure (Struct)
  • un tableau (Array)

La partie SOAP Fault permet d'indiquer qu'une erreur est survenue lors des traitements du service web. Cette partie peut être composée de 4 éléments :

  • faultcode : indique le type de l'erreur (VersionMismatch en cas d'incompatibilité avec la version de SOAP utilisée, MustUnderstand en cas de problème dans le header du message, Client en cas de manque d'informations de la part du client, Server en cas de problème d'exécution des traitements par le serveur)
  • faultstring : message décrivant l'erreur
  • faultactor : URI de l'élément ayant déclenché l'erreur
  • faultdetail

 

69.2.1.2. L'encodage des messages SOAP

Deux formats de messages SOAP sont définis :

  • remote procedure call : (RPC) permet l'invocation d'opérations qui peuvent retourner un résultat.
  • message oriented (Document) : données au format XML définies dans un schéma XML

Les règles d'encodage (Encoding rules) précisent les mécanismes de sérialization des données dans un message. Il existe deux types :

  • Encoded : les paramètres d'entrée de la requête et les données de la réponse sont encodées en XML dans le corps du message selon un format particulier à SOAP
  • Literal : les données n'ont pas besoin d'être encodées de façon particulière : elles sont directement encodées en XML selon un schéma défini dans le WSDL

Le style et le type d'encodage permettent de définir comment les données seront sérialisées et désérialisées dans les requêtes et les réponses.

La combinaison du style et du type d'encodage peut prendre plusieurs valeurs :

  • RPC/Encoded
  • RPC/Literal
  • Document Encoded : cette combinaison n'est pas implémentée
  • Document/Literal 
  • Wrapped Document/Literal : extension du Document/Literal proposé par Microsoft

Le style RPC/Encoded a largement été utilisé au début des services web : actuellement ce style est en cours d'abandon par l'industrie au profit du style Document/Literal. C'est pour cette raison que le style RPC/Encoded n'est pas intégré dans le WS-I Basic Profile 1.1.

Le style et le type d'encodage sont précisés dans le WSDL. L'appel du service web doit obligatoirement se faire dans le style précisé dans le WSDL puisque celui-ci détermine le format des messages échangés.

 

69.2.1.3. Les différentes versions de SOAP

Les versions de SOAP

  • 1.0 :
  • 1.1 :
  • 1.2 : permet l'utilisation de requêtes HTTP de type GET

Les spécifications de SOAP 1.2 sont composées de plusieurs parties :

La version 1.2 des spécifications de SOAP est plus précise pour réduire les ambigüités qui pouvaient conduire à des problèmes d'interopérabilité entre différentes implémentations.

SOAP 1.2 propose un support pour des protocoles de transport différents de HTTP. La sérialisation de messages n'est pas obligatoirement en XML mais peut utiliser des formats binaires (XML Infoset par exemple).

 

69.2.2. WSDL

WSDL (acronyme de Web Service Description Language) est utilisé pour fournir une description d'un service web afin de permettre son utilisation. C'est une recommandation du W3C.

Pour permettre à un client de consommer un service web, ce dernier a besoin d'une description détaillée du service avant de pouvoir interagir avec lui. Un WSDL fournit cette description dans un document XML. WSDL joue un rôle important dans l'architecture des services en assurant la partie description : il contient toutes les informations nécessaires à l'invocation du service qu'il décrit.

La description WSDL d'un service web comprend une définition du service, les types de données utilisés notamment dans le cas de types complexes, les opérations utilisables, le protocole utilisé pour le transport et l'adresse d'appel.

C'est un document XML qui décrit un service web de manière indépendante de tout langage. Il permet l'appel de ses opérations et l'exploitation des réponses (les paramètres, le format des messages, le protocole utilisé, ...).

WSDL est conçu pour être indépendant de tout protocoles. Ceci rend le standard WSDL flexible mais aussi plus complexe à comprendre. Comme SOAP et HTTP sont les deux protocoles les plus couramment utilisés pour implémenter les services web, le standard WSDL intègre un support de ces deux protocoles.

L'utilisation de XML permet à des outils de différents systèmes, plate-formes et langages d'utiliser le contenu d'un WSDL pour générer du code permettant de consommer un service web. Les moteurs SOAP proposent en général un outil qui va lire le WSDL et générer les classes requises pour utiliser un service web avec la technologie du moteur SOAP. Le code généré utilise un moteur SOAP qui masque toute la tuyauterie du protocole utilisé et des messages échangés lors de la consommation de services web en agissant comme un proxy. Par exemple, Axis propose l'outil WSDL2Java pour la génération de ces classes à partir du WSDL.

Pour assurer une meilleure interopérabilité, WS-I Basic Profil 1.0 oblige à utiliser WSDL et les schémas XML pour la description des services web.

Les spécifications de WSDL sont consultables à l'url : http://www.w3.org/standards/techs/wsdl#w3c_all

 

69.2.2.1. Le format général d'un WSDL

Un document WSDL définit plusieurs éléments :

  • Type : la définition des types de données utilisés
  • Message : la définition de la structure d'un message en lui attribuant un nom et en décrivant les éléments qui le composent avec un nom et un type
  • PortType : la description de toutes les opérations proposées par le service web (interface du service) et identification de cet ensemble avec un nom
  • Operation : la description d'une action proposée par le service web notamment en précisant les messages en entrée (input) et en sortie (output)
  • Binding : la description du protocole de transport et d'encodage utilisé par un PortType afin de pouvoir invoquer un service web
  • Port : référence un Binding (généralement cela correspond à l'url d'invocation du service web)
  • Service : c'est un ensemble de ports

Un WSDL est un document XML dont le tag racine est <definitions> et qui utilise l'espace de nommage "http://schemas.xmlsoap.org/wsdl/".

Un WSDL est virtuellement composé de deux parties :

  • des définitions abstraites : celles-ci concernent l'interface du service (types, message, portType). Ces informations sont exploitées dans le code du client
  • des définitions concrètes : celles-ci concernent l'invocation du service (binding, service). Ces informations sont exploitées par le moteur SOAP.

Le contenu du WSDL d'un service nommé MonService est de la forme :

Exemple :
<!-Structure d'un WSDL -->
<definitions name="MonService"
targetNamespace="http://com.jmdoudoux.test.ws.monservice/"
xmlns="http://schemas.xmlsoap.org/wsdl/">
   <!-- Définitions abstraites -->
   <types> ... </types>
   <message> ... </message>
   <portType> ... </portType>

   <!-- Définitions concrètes -->
   <binding> ... </binding>
   <service> ... </service>
</definitions>

L'ordre de définition des informations dans un WSDL facilite les traitements de ce document par une machine. Pour une exploitation par un humain, il est plus facile de lire le WSDL en commençant par la fin.

Exemple :
<?xml version="1.0" encoding="UTF-8" ?> 
 <wsdl:definitions targetNamespace="http://axis.test.jmdoudoux.com" 
      xmlns:apachesoap="http://xml.apache.org/xml-soap" 
      xmlns:impl="http://axis.test.jmdoudoux.com" 
      xmlns:intf="http://axis.test.jmdoudoux.com" 
      xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" 
      xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
      xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" 
      xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <!-- 
WSDL created by Apache Axis version: 1.3
Built on Oct 05, 2005 (05:23:37 EDT)

  --> 
  <wsdl:message name="additionnerRequest">
  <wsdl:part name="valeur1" type="xsd:int" /> 
  <wsdl:part name="valeur2" type="xsd:int" /> 
  </wsdl:message>
  <wsdl:message name="additionnerResponse">
  <wsdl:part name="additionnerReturn" type="xsd:long" /> 
  </wsdl:message>
 <wsdl:portType name="Calculer">
  <wsdl:operation name="additionner" parameterOrder="valeur1 valeur2">
  <wsdl:input message="impl:additionnerRequest" name="additionnerRequest" /> 
  <wsdl:output message="impl:additionnerResponse" name="additionnerResponse" /> 
  </wsdl:operation>
  </wsdl:portType>
  <wsdl:binding name="CalculerSoapBinding" type="impl:Calculer">
  <wsdlsoap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http" /> 
  <wsdl:operation name="additionner">
  <wsdlsoap:operation soapAction="" /> 
  <wsdl:input name="additionnerRequest">
  <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" 
    namespace="http://axis.test.jmdoudoux.com" use="encoded" /> 
  </wsdl:input>
  <wsdl:output name="additionnerResponse">
  <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" 
    namespace="http://axis.test.jmdoudoux.com" use="encoded" /> 
  </wsdl:output>
  </wsdl:operation>
  </wsdl:binding>
  <wsdl:service name="CalculerService">
  <wsdl:port binding="impl:CalculerSoapBinding" name="Calculer">
  <wsdlsoap:address location="http://localhost:8080/TestWS/services/Calculer" /> 
  </wsdl:port>
  </wsdl:service>
  </wsdl:definitions>

Un document WSDL est un document XML dont le tag racine est <definitions>. Généralement, ce tag contient la définition des différents espaces de nommages qui seront utilisés dans le document XML.

L'espace de nommage du document WSDL est défini.

Exemple :

xmlns="http://schemas.xmlsoap.org/wsdl/"  (déclaration de l'espace de nommage par défaut)
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"

L'espace de nommage de la norme Schema XML est défini.

Exemple :

xmlns:xsd="http://www.w3.org/2001/XMLSchema"

Plusieurs autres espaces de nommages standard sont généralement définis selon les protocoles utilisés.

Exemple :

xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/"

Il est possible de trouver la définition d'espaces de nommages propres à l'implémentation.

Exemple :

xmlns:apachesoap="http://xml.apache.org/xml-soap"

Un ou plusieurs espaces de nommages sont définis pour le service web lui-même.

Remarque : les préfixes utilisés pour ces espaces de nommages peuvent être différents selon l'implémentation des services web mise en oeuvre

Dans un document WSDL, les différentes entités se référencent mutuellement grâce à leur nom complet (espace de nommage et nom).

L'élément racine d'un WSDL est le tag <definitions>.

Le tag <definitions> peut contenir plusieurs tags fils :

  • <types> : description des types de données utilisés
  • <message> : description des messages qui peuvent être composés de plusieurs types
  • <portType> : description des opérations du endpoint sous la forme d'échanges de messages. Ceci correspond à l'interface du service
  • <binding> : description du protocole et spécification du format des données pour un portType
  • <service> : description des endpoints du service (binding et uri)

 

69.2.2.2. L'élément Types

Le tag <definitions> ne peut avoir qu'un seul tag fils <types>.

L'élément <types> contient une définition des différents types de données qui seront utilisés.

Cette définition peut être faite sous plusieurs formats mais l'utilisation des schémas XML est recommandée. Le WS-I Basic Profile impose que cette description soit faite avec des schémas XML.

L'élément <types> peut avoir aucun, un ou plusieurs éléments fils <schema> ayant pour espace de nommage "http://www.w3.org/2001/XMLSchema".

Chaque structure de données est décrite en utilisant la norme schéma XML.

L'élément <types> peut donc avoir plusieurs schémas XML comme éléments fils. Ces schémas peuvent décrire des types simples (element) ou complexes (complexType).

 

69.2.2.3. L'élément Message

Le tag <definitions> peut avoir plusieurs tags fils <message>. Le tag <message> décrit un message qui est utilisé en tant que requête ou réponse lors de l'invocation d'une opération : il contient une définition des paramètres pour un message échangé en entrée ou en sortie..

Le tag <message> peut avoir un ou plusieurs tags <part>. Le tag <part> possède un attribut "name" pour permettre d'y faire référence et utilise un attribut "element" (pour le style document qui représente l'élément XML inséré dans le body) ou un attribut "type" (pour le style RPC qui représente les paramètres de l'opération).

 

69.2.2.4. L'élément PortType/Interface

En WSDL, un échange de messages est une opération qui peut donc avoir une requête en entrée et une réponse en sortie.

Le tag <definitions> peut avoir un ou plusieurs tags fils <typePort>. Le tag <portType> décrit l'interface d'un service web.

Le terme typePort est particulièrement ambigu : il correspond à une description de l'interface du service. Le tag <interface> est utilisé à partir de la version 2.0 de WSDL.

Le tag <typePort> possède un attribut name qui permet d'y faire référence.

Il contient un ensemble d'opérations chacune définie dans un tag fils <operation> qui possède un attribut name permettant d'y faire référence.

Le tag <operation> peut avoir les tags fils <input>, <output> et <fault>. La présence et l'ordre des deux premiers tags définissent le mode d'invocation d'une opération nommé MEP (Message Exchance Pattern).

MEP

Description

One-way

L'endpoint reçoit un message sans fournir de réponse : <input> uniquement

Request-response

L'endpoint reçoit un message et envoie la réponse correspondante : <input> et <output>

Notification

L'endpoint envoie un message sans avoir de réponse : <output> uniquement

Solicit-response

L'endpoint envoie un message et reçoit la réponse correspondante : <output> et <input>


Le support de ces types d'opérations dépend de l'implémentation du moteur SOAP utilisé.

L'attribut message des tags <input> et <output> fait référence à un tag <message> par son nom.

 

69.2.2.5. L'élément Binding

La description du service doit aussi fournir des informations pour invoquer le service :

  • le protocole utilisé pour le transport du message
  • l'encodage du message : style et mécanisme d'encodage

Un binding permet de fournir des détails sur la façon dont les données sont transportées.

Un service peut avoir plusieurs bindings mais chacun doit se faire sur une URI unique nommée endpoint.

Le tag <definitions> peut avoir un ou plusieurs tags fils <binding>.

Il permet de définir pour un portType le protocole de transport utilisé et le mode d'encodage des messages.

Le tag <binding> possède un attribut name qui permet d'y faire référence et un attribut type qui permet de faire référence au portType concerné de façon nominative.

Le détail des informations sur le protocole et le mode d'encodage sont des extensions spécifiques comme celle fournie en standard relative à SOAP.

Ainsi le tag fils <soap:binding> est utilisé pour préciser que c'est la version 1.1 de SOAP qui sera utilisée. Son attribut style permet de préciser le style du message : les valeurs possibles sont rpc ou document. Son attribut transport permet de préciser le procotole de transport à utiliser, généralement "http://schemas.xmlsoap.org/soap/http" pour le protocole http.

Le tag <binding> possède un tag fils <operation> pour chaque opération. Le tag <operation> peut avoir plusieurs tags fils.

Le tag fils <soap:operation> permet de définir par son attribut "soapAction" la valeur du header http correspondant. Selon les spécifications WS-I BP, l'attribut "soapAction" doit toujours avoir la valeur chaîne vide.

Les tags <input> et <output> permettent de fournir des précisions sur l'encodage du corps des messages.

Le tag fils <soap:body> permet, par son attribut "use", de préciser comment le corps de message sera encodé : les valeurs possibles sont encoded et document.

L'utilisation de l'encodage "rpc" précise que le corps du message sera une représentation XML des paramètres ou de la valeur de retour de la méthode invoquée.

L'utilisation de l'encodage "document" précise que le corps du message sera un message XML.

 

69.2.2.6. L'élément Service

Le tag <definitions> ne peut avoir qu'un seul tag fils <service>.

Un service possède un nom précisé dans la valeur de son attribut name.

Un service est composé d'un ou plusieurs ports qui en SOAP correspondent à des endpoints. Chaque port est associé à un binding en utilisant l'attribut binding qui a comme valeur le nom d'un binding défini.

Les tags fils du tag <port> sont spécifiques au binding utilisé : ce sont des extensions qui précisent le endpoint selon le binding. Par exemple pour préciser l'url d'un service web utilisant http, il faut utiliser le tag <address> en fournissant l'url du endpoint comme valeur de l'attribut location. Le tag <endpoint> est utilisé à partir de la version 2.0 de WSDL.

Un port permet de décrire la façon d'accéder au service, ce qui correspond généralement à l'url d'un endpoint et à un binding.

 

69.2.3. Les registres et les services de recherche

 

69.2.3.1. UDDI

UDDI, acronyme de Universal Description, Discovery and Integration, est utilisé pour publier et rechercher des services web. C'est un protocole et un ensemble de services pour utiliser un annuaire afin de stocker les informations concernant les services web et de permettre à un client de les retrouver. Les spécifications sont rédigées par l'Oasis.

UDDI est une spécification pour permettre la publication et la recherche d'informations sur des entreprises et les services web qu'elles proposent. UDDI permet à une entreprise de s'inscrire dans l'annuaire, d'y enregistrer et de publier ses services web. Il est alors possible d'accéder à l'annuaire et de rechercher un service particulier.

Le site web officiel d'UDDI est à l'url : http://uddi.xml.org

Un annuaire UDDI contient une description de services web mais aussi des entreprises qui les proposent. Ainsi, il est possible avec UDDI de faire une recherche par entreprise ou par activité.

Les données incluses dans un annuaire UDDI sont classées dans trois catégories :

  • les pages blanches (white pages) : elles contiennent les informations générales sur une entreprise
  • les pages jaunes (yellow pages) : elles permettent une catégorisation des entreprises
  • les pages vertes (green pages) : elles contiennent les informations techniques sur les services proposés

Il est possible d'utiliser un annuaire UDDI en interne dans une entreprise mais il existe aussi des annuaires UDDI globaux nommés UBR (UDDI Business Registry).

Il existe plusieurs versions d'UDDI :

UDDI n'est pas un élément indispensable à la mise en oeuvre des services web comme peut l'être XML, WSDL ou SOAP.

UDDI est une spécification d'annuaire accessible sous la forme de services web de type SOAP que ce soit pour les recherches ou les mises à jour.

Le site http://xmethods.net propose une liste des services web publics.

 

69.2.3.2. Ebxml

 

en construction
La suite de cette section sera développée dans une version future de ce document

 

69.3. Les différents formats de services web SOAP

Un message SOAP peut être formaté de plusieurs façons en fonction de son style et de son type d'encodage.

Il existe deux styles de services web reposant sur SOAP : RCP et Document.

En plus du style, il existe deux types d'encodages : Encoded et Literal. Cela permet de définir quatre combinaisons mais généralement les combinaisons utilisées sont RPC/Encoded et Document/Literal. La combinaison Document/Encoded n'est supportée par aucune implémentation.

De plus, Microsoft est à l'origine d'un cinquième format qui bien que non standardisé est largement utilisé car il est mis en oeuvre par défaut dans la plate-forme.Net et il offre un bon compromis entre performance et restrictions d'utilisation.

Style / Type d'encodage

Encoded

Literal

RPC

RPC / Encoded

RPC / Literal

Document

Document / Encoded

Document / Literal

Document / Literal wrapped


Il y a deux façons de structurer un document SOAP : RPC et Document. Initialement, avant la diffusion de sa première version, SOAP ne permettait que le style RPC. La version 1.0 s'est vue ajouter le support pour le style Document.

Le style RPC est parfaitement structuré alors que le type Document n'a pas de structure imposée mais son contenu peut être facilement validé grâce à un schéma XML ou traité puisque c'est un document XML. Avec le style document, il est donc possible de structurer librement le corps du message grâce au schéma XML.

Les différents styles sont :

Style

Description

RPC

Les messages contiennent le nom de l'opération

Paramètres en entrée multiples et valeur de retour

Document

Les messages ne contiennent pas le nom de l'opération

Un document XML en entrée et en retour


Les deux désignations pour le style d'encodage (RPC et Document) peuvent être trompeuses car elles peuvent induire que le style RPC est utilisé pour l'invocation d'opérations distantes et que le style document est utilisé pour l'échange de messages. En fait, le style n'a rien à voir avec un modèle de programmation mais il permet de préciser comment le message SOAP est encodé.

Dans le style RPC, le corps du message (tag <soap:body>) contient un élément qui est le nom de l'opération du service. Cet élément contient un élément fils pour chaque paramètre.

Dans le style Document, le corps du message (tag <soap:body>) contient directement un document xml dont tous les composants doivent être décrits dans un ou plusieurs schémas XML. Le moteur Soap est alors responsable du mapping entre le contenu du message et les objets du serveur.

Les types d'encodage pour sérialiser les messages en XML sont :

Encodage

Description

Encoded

Aussi appelé SOAP encoding car l'encodage est spécifique à SOAP sans utiliser de schéma XML

Literal

L'encodage du message repose sur les schémas XML

Literal wrapped

Idem Literal avec en plus l'encapsulation de chaque message dans un tag qui contient le nom de l'opération. Ce format est défini par Microsoft qui l'utilise dans sa plate-forme .Net


Le type d'encodage Literal propose que le contenu du corps (body) soit validé par un schéma XML donné : chaque élément qui correspond à un paramètre ou à la valeur de retour est décrit dans un schéma XML.

Le type d'encodage Encoded utilise un ensemble de règles reposant sur les types de données des schémas XML pour encoder les données mais le message ne respecte pas de schéma particulier : chaque élément qui correspond à un paramètre ou à la valeur de retour contient la description de la donnée sous la forme d'attributs spécifiés dans la norme Soap (type, null ou pas, ...)

Le type d'encodage Encoded est particulièrement adapté lors de l'utilisation d'un graphe d'objets cyclique car chaque type d'objet ne sera défini qu'une seule fois. Avec l'encodage Literal, chaque élément est répété dans le document.

Le type d'encodage Literal permet une manipulation du document XML qui constitue le message (validation par un schéma XML, parsing du document, transformation à l'aide d'une feuille de style XSLT, ...)

Le format RPC encoded repose sur des types définis par SOAP alors que les formats RPC Literal et Document Literal repose sur les types du schéma XML.

Il existe donc plusieurs formats utilisables pour un message SOAP :

  • RPC Encoded : c'est le premier format historiquement proposé par SOAP mais son utilisation est de moins en moins fréquente
  • RPC Literal :
  • Document Literal :
  • Document Literal Wrapped :
  • Document Encoded : ce format n'est pas supporté actuellement par les moteurs de services web

Ces différents styles et types d'encodages sont à l'origine de difficultés d'interopérabilité au début des services web car la plate-forme .Net utilisait le style Document par défaut et les implémentations sur la plate-forme Java utilisaient plutôt le style RPC.

Au début de l'utilisation de SOAP, c'est donc le format RPC encoding qui était utilisé. Depuis, c'est plutôt le format Document/Literal ou RPC/Literal qui est recommandé notamment par les spécifications WS-I Basic Profile.

Les sections suivantes vont utiliser la classe d'implémentation du service web ci-dessous avec Axis.

Exemple :
package com.jmdoudoux.test.axis;

public class Calculer {
 
  public long additionner(int valeur1, int valeur2) {
    return valeur1+valeur2;
  }       
}

Les sections suivantes vont utiliser la classe d'implémentation du service web ci-dessous avec Metro

Exemple :
package com.jmdoudoux.test.ws;

import javax.jws.WebService;

@WebService
public class Calculer {
 
  public long additionner(int valeur1, int valeur2) {
    return valeur1+valeur2;
  }       
}

 

69.3.1. Le format RPC Encoding

Ce format de messages est le plus ancien et le plus simple à mettre en oeuvre pour le développeur.

La structure du corps du message avec le style RPC est imposée. Par exemple, pour une requête, il doit contenir le nom de la méthode ainsi que ses paramètres. Cette structure est donc de la forme :

Exemple :
<soapenv:Body>
<ns0:nom_de_la_methode xmlns:ns0="uri_de_l_espace_de_nommage" 
  soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
  <nom_param_1 xsi:type="xsd:type_param_1">valeur_parametre_1</nom_param_1> 
  <nom_param_2 xsi:type="xsd:type_param_2">valeur_parametre_2</nom_param_2> 
  </ns0: nom_de_la_methode>
  </soapenv:Body>
  </soapenv:Envelope>

Le message réponse a une forme similaire.

Le type des paramètres peut être simple ou plus complexe (par exemple un objet qui encapsule des données de types simples ou d'autres objets).

Attention : RPC Encoding n'est pas conforme à la spécification WS-I Basic Profile

Exemple : Le fichier WSDL

Exemple :
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions targetNamespace="http://axis.test.jmdoudoux.com" 
                  xmlns:apachesoap="http://xml.apache.org/xml-soap" 
                  xmlns:impl="http://axis.test.jmdoudoux.com" 
                  xmlns:intf="http://axis.test.jmdoudoux.com" 
                  xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" 
                  xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
                  xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" 
                  xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<!--WSDL created by Apache Axis version: 1.3
Built on Oct 05, 2005 (05:23:37 EDT)-->
   <wsdl:message name="additionnerRequest">
      <wsdl:part name="valeur1" type="xsd:int"/>
      <wsdl:part name="valeur2" type="xsd:int"/>
   </wsdl:message>
   <wsdl:message name="additionnerResponse">
      <wsdl:part name="additionnerReturn" type="xsd:long"/>
   </wsdl:message>
   <wsdl:portType name="Calculer">
      <wsdl:operation name="additionner" parameterOrder="valeur1 valeur2">
         <wsdl:input message="impl:additionnerRequest" name="additionnerRequest"/>
         <wsdl:output message="impl:additionnerResponse" name="additionnerResponse"/>
      </wsdl:operation>
   </wsdl:portType>
   <wsdl:binding name="CalculerSoapBinding" type="impl:Calculer">
      <wsdlsoap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
      <wsdl:operation name="additionner">
         <wsdlsoap:operation soapAction=""/>
         <wsdl:input name="additionnerRequest">
            <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" 
              namespace="http://axis.test.jmdoudoux.com" use="encoded"/>
         </wsdl:input>
         <wsdl:output name="additionnerResponse">
            <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" 
              namespace="http://axis.test.jmdoudoux.com" use="encoded"/>
         </wsdl:output>
      </wsdl:operation>
   </wsdl:binding>
   <wsdl:service name="CalculerService">
      <wsdl:port binding="impl:CalculerSoapBinding" name="Calculer">
         <wsdlsoap:address location="http://localhost:8080/TestWS/services/Calculer"/>
      </wsdl:port>
   </wsdl:service>
</wsdl:definitions>

Exemple : descripteur Axis

Exemple :
<service name="Calculer" provider="java:RPC">
  <operation name="additionner" qname="ns1:additionner" 
             returnQName="additionnerReturn" 
             returnType="xsd:long" 
             soapAction="" 
             xmlns:ns1="http://axis.test.jmdoudoux.com" 
             xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   <parameter name="valeur1" type="xsd:int"/>
   <parameter name="valeur2" type="xsd:int"/>
  </operation>
  <parameter name="allowedMethods" value="additionner"/>
  <parameter name="typeMappingVersion" value="1.2"/>
  <parameter name="wsdlPortType" value="Calculer"/>
  <parameter name="className" value="com.jmdoudoux.test.axis.Calculer"/>
  <parameter name="wsdlServicePort" value="Calculer"/>
  <parameter name="wsdlTargetNamespace" value="http://axis.test.jmdoudoux.com"/>
  <parameter name="wsdlServiceElement" value="CalculerService"/>
</service>

La requête SOAP

Exemple :
<?xml version="1.0" encoding="UTF-8" ?> 
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
                  xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
                  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <soapenv:Body>
    <ns0:additionner 
      xmlns:ns0="http://axis.test.jmdoudoux.com" 
      soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
      <valeur1 xsi:type="xsd:int">10</valeur1> 
      <valeur2 xsi:type="xsd:int">20</valeur2> 
    </ns0:additionner>
  </soapenv:Body>
</soapenv:Envelope>

La réponse SOAP

Exemple :
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
                  xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
                  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <soapenv:Body>
    <ns1:additionnerResponse 
      xmlns:ns1="http://axis.test.jmdoudoux.com" 
      soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
      <additionnerReturn href="#id0" /> 
    </ns1:additionnerResponse>
    <multiRef xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" 
              id="id0" soapenc:root="0" 
              soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" 
              xsi:type="xsd:long">30</multiRef> 
  </soapenv:Body>
</soapenv:Envelope>

Avantages :

  • ce format est facilement compréhensible par un être humain
  • le nom de l'opération à invoquer est inclus dans le message ce qui rend le dispatching par le moteur SOAP vers la méthode correspondante très facile
  • la gestion des valeurs null est supportée en standard

Inconvénients :

  • il n'est pas possible de valider le message dans la mesure où seuls les paramètres sont définis dans un schéma. Le reste du contenu du corps de l'enveloppe est défini directement dans le WSDL.
  • ce mode peut poser des problèmes d'intéropérabilité : il est d'ailleurs incompatible avec les spécifications WS-I Basic Profile. Son utilisation n'est donc plus recommandée
  • c'est le type d'encodage qui a les moins bonnes performances et qui génère les messages les plus verbeux notamment à cause de l'indication du type de chaque donnée

 

69.3.2. Le format RPC Literal

Les messages de type RPC/Literal sont encodés comme des appels RPC avec une description des paramètres et des valeurs de retour décrites chacune avec son propre schéma XML.

Le moteur Soap utilisé pour l'exemple de cette section est Metro version 1.5.

Exemple :
import javax.jws.soap.SOAPBinding.Use;

@WebService
@SOAPBinding(style=Style.RPC, use=Use.LITERAL, parameterStyle=ParameterStyle.BARE)
public class Calculer {

  public long additionner(Valeurs valeurs) {
    return valeurs.getValeur1()+valeurs.getValeur2();
  } 
}

Exemple :
<?xml version="1.0" encoding="UTF-8"?>
<endpoints xmlns="http://java.sun.com/xml/ns/jax-ws/ri/runtime"
      version="2.0">
  <endpoint name="CalculerWS" implementation="com.jmdoudoux.test.ws.Calculer"
      url-pattern="/services/CalculerWS" />
</endpoints>

Le fichier WSDL

Exemple :
<?xml version='1.0' encoding='UTF-8'?>
  <!--
    Published by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is
    JAX-WS RI 2.1.7-hudson-48-.
  -->
  <!--
    Generated by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is
    JAX-WS RI 2.1.7-hudson-48-.
  -->
<definitions
  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://ws.test.jmdoudoux.com/"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/wsdl/"
  targetNamespace="http://ws.test.jmdoudoux.com/" name="CalculerService">
  <types>
    <xsd:schema>
      <xsd:import namespace="http://ws.test.jmdoudoux.com/"
        schemaLocation="http://localhost:8089/TestMetro/services/CalculerWS?xsd=1" />
    </xsd:schema>
  </types>
  <message name="additionner">
    <part name="additionner" element="tns:additionner" />
  </message>
  <message name="additionnerResponse">
    <part name="additionnerResponse" element="tns:additionnerResponse" />
  </message>
  <portType name="Calculer">
    <operation name="additionner">
      <input message="tns:additionner" />
      <output message="tns:additionnerResponse" />
    </operation>
  </portType>
  <binding name="CalculerPortBinding" type="tns:Calculer">
    <soap:binding transport="http://schemas.xmlsoap.org/soap/http"
      style="rpc" />
    <operation name="additionner">
      <soap:operation soapAction="" />
      <input>
        <soap:body use="literal" namespace="http://ws.test.jmdoudoux.com/" />
      </input>
      <output>
        <soap:body use="literal" namespace="http://ws.test.jmdoudoux.com/" />
      </output>
    </operation>
  </binding>
  <service name="CalculerService">
    <port name="CalculerPort" binding="tns:CalculerPortBinding">
      <soap:address location="http://localhost:8089/TestMetro/services/CalculerWS" />
    </port>
  </service>
</definitions>

La description est faite dans un schéma dédié

Exemple :
<?xml version='1.0' encoding='UTF-8'?>
<xs:schema xmlns:tns="http://ws.test.jmdoudoux.com/" 
           xmlns:xs="http://www.w3.org/2001/XMLSchema" 
           version="1.0" targetNamespace="http://ws.test.jmdoudoux.com/">
<xs:element name="additionner" nillable="true" type="tns:valeurs" />
  <xs:element name="additionnerResponse" type="xs:long" />
  <xs:complexType name="valeurs">
    <xs:sequence>
      <xs:element name="valeur1" type="xs:int" />
      <xs:element name="valeur2" type="xs:int" />
    </xs:sequence>
  </xs:complexType>
</xs:schema>

Le premier élément du tag <body> du message désigne la méthode à invoquer

La requête SOAP

Exemple :
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
                  xmlns:ws="http://ws.test.jmdoudoux.com/">
   <soapenv:Header/>
   <soapenv:Body>
      <ws:additionner>
         <ws:additionner>
            <valeur1>20</valeur1>
            <valeur2>30</valeur2>
         </ws:additionner>
      </ws:additionner>
   </soapenv:Body>
</soapenv:Envelope>

La réponse SOAP

Exemple :
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
   <S:Body>
      <ns2:additionnerResponse xmlns:ns2="http://ws.test.jmdoudoux.com/">
      50</ns2:additionnerResponse>
   </S:Body>
</S:Envelope>

Avantages :

  • supporté par le WS-I Basic Profile
  • le nom de la méthode invoquée est inclus dans le message

Inconvénient :

  • il est difficile de valider le message

 

69.3.3. Le format Document encoding

Ce type d'encodage n'est supporté par aucun moteur de services web.

 

69.3.4. Le format Document Literal

Pour respecter le WS-I BP, le tag <soap:body> d'un message Soap encodé en document Literal ne peut avoir qu'un seul élément fils.

L'exemple de cette section va donc utiliser une version légèrement différente du service web qui attend en paramètre un bean encapsulant les données à calculer.

Exemple :
package com.jmdoudoux.test.ws.axis;
      
public class CalculerWS {
 
  public long additionner(Valeurs valeurs) {
    return valeurs.getValeur1()+valeurs.getValeur2();
  }           
}

La classe Valeurs est un POJO qui encapsule les paramètres requis par la méthode.

Exemple :
package com.jmdoudoux.test.ws;

public class Valeurs {
  private int valeur1;
  private int valeur2;

  public Valeurs() {
    super();
  }

  public Valeurs(int valeur1, int valeur2) {
    super();
    this.valeur1 = valeur1;
    this.valeur2 = valeur2;
  }

  public synchronized int getValeur1() {
    return valeur1;
  }

  public synchronized void setValeur1(int valeur1) {
    this.valeur1 = valeur1;
  }

  public synchronized int getValeur2() {
    return valeur2;
  }

  public synchronized void setValeur2(int valeur2) {
    this.valeur2 = valeur2;
  }
}

Descripteur Axis 1.x

Exemple :
<?xml version="1.0" encoding="UTF-8"?>
<deployment xmlns="http://xml.apache.org/axis/wsdd/"
            xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
  <service name="CalculerWS" provider="java:RPC" style="document"
    use="literal">
    <parameter name="wsdlTargetNamespace" value="http://axis.ws.test.jmdoudoux.com" />
    <parameter name="wsdlServiceElement" value="CalculerWSService" />
    <parameter name="schemaQualified" value="http://axis.ws.test.jmdoudoux.com" />
    <parameter name="wsdlServicePort" value="CalculerWS" />
    <parameter name="className" value="com.jmdoudoux.test.ws.axis.CalculerWS" />
    <parameter name="wsdlPortType" value="CalculerWS" />
    <parameter name="typeMappingVersion" value="1.2" />
    <operation xmlns:retNS="http://axis.ws.test.jmdoudoux.com"
      xmlns:rtns="http://www.w3.org/2001/XMLSchema" name="additionner"
      qname="additionner" returnQName="retNS:additionnerReturn" returnType="rtns:long"
      soapAction="">
      <parameter xmlns:pns="http://axis.ws.test.jmdoudoux.com"
        xmlns:tns="http://axis.ws.test.jmdoudoux.com" qname="pns:valeurs"
        type="tns:Valeurs" />
    </operation>
    <parameter name="allowedMethods" value="additionner" />

    <typeMapping xmlns:ns="http://axis.ws.test.jmdoudoux.com"
      qname="ns:Valeurs" type="java:com.jmdoudoux.test.ws.axis.Valeurs"
      serializer="org.apache.axis.encoding.ser.BeanSerializerFactory"
      deserializer="org.apache.axis.encoding.ser.BeanDeserializerFactory"
      encodingStyle="" />
  </service>
</deployment>

Le fichier WSDL

Exemple :
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions targetNamespace="http://axis.ws.test.jmdoudoux.com" 
                  xmlns:apachesoap="http://xml.apache.org/xml-soap" 
                  xmlns:impl="http://axis.ws.test.jmdoudoux.com" 
                  xmlns:intf="http://axis.ws.test.jmdoudoux.com" 
                  xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
                  xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" 
                  xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<!--WSDL created by Apache Axis version: 1.4
Built on Apr 22, 2006 (06:55:48 PDT)-->
 <wsdl:types>
  <schema elementFormDefault="qualified" 
          targetNamespace="http://axis.ws.test.jmdoudoux.com" 
          xmlns="http://www.w3.org/2001/XMLSchema">
   <complexType name="Valeurs">
    <sequence>
     <element name="valeur1" type="xsd:int"/>
     <element name="valeur2" type="xsd:int"/>
    </sequence>
   </complexType>
   <element name="valeurs" type="impl:Valeurs"/>
   <element name="additionnerReturn" type="xsd:long"/>
  </schema>
 </wsdl:types>
   <wsdl:message name="additionnerResponse">
      <wsdl:part element="impl:additionnerReturn" name="additionnerReturn"/>
   </wsdl:message>
   <wsdl:message name="additionnerRequest">
      <wsdl:part element="impl:valeurs" name="valeurs"/>
   </wsdl:message>
   <wsdl:portType name="CalculerWS">
      <wsdl:operation name="additionner" parameterOrder="valeurs">
         <wsdl:input message="impl:additionnerRequest" name="additionnerRequest"/>
         <wsdl:output message="impl:additionnerResponse" name="additionnerResponse"/>
      </wsdl:operation>
   </wsdl:portType>
   <wsdl:binding name="CalculerWSSoapBinding" type="impl:CalculerWS">
      <wsdlsoap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
      <wsdl:operation name="additionner">
         <wsdlsoap:operation soapAction=""/>
         <wsdl:input name="additionnerRequest">
            <wsdlsoap:body use="literal"/>
         </wsdl:input>
         <wsdl:output name="additionnerResponse">
            <wsdlsoap:body use="literal"/>
         </wsdl:output>
      </wsdl:operation>
   </wsdl:binding>
   <wsdl:service name="CalculerWSService">
      <wsdl:port binding="impl:CalculerWSSoapBinding" name="CalculerWS">
         <wsdlsoap:address location="http://localhost:8089/TestsAxisWS/services/CalculerWS"/>
      </wsdl:port>
   </wsdl:service>
</wsdl:definitions>

La requête SOAP

Exemple :
<soapenv:Envelope 
   xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
   xmlns:axis="http://axis.ws.test.jmdoudoux.com">
   <soapenv:Header/>
   <soapenv:Body>
      <axis:valeurs>
         <axis:valeur1>20</axis:valeur1>
         <axis:valeur2>30</axis:valeur2>
      </axis:valeurs>
   </soapenv:Body>
</soapenv:Envelope>

La réponse SOAP

Exemple :
<soapenv:Envelope 
   xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
   xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <soapenv:Body>
      <additionnerReturn 
        xmlns="http://axis.ws.test.jmdoudoux.com">
        50
      </additionnerReturn>
   </soapenv:Body>
</soapenv:Envelope>

Avantages :

  • le contenu du corps de l'enveloppe peut être validé puisque tous les éléments sont définis dans un schéma
  • supporté par le WS-I Basic Profile avec quelques contraintes

Inconvénients :

  • le fichier WSDL est plus compliqué à comprendre pour un être humain
  • le nom de l'opération n'apparaît pas dans la requête SOAP : le mapping vers la méthode du service web à invoquer est donc plus limité puisqu'il doit se faire sur la séquence de paramètres
  • il n'est donc pas possible dans un même service web d'avoir deux méthodes avec la même liste de paramètres
  • le nom de l'opération n'est pas contenu dans le message ce qui impose des contraintes au niveau des signatures des interfaces des opérations
  • pour respecter le WS-I BP le tag <soap:body> ne peut avoir qu'un seul tag fils

 

69.3.5. Le format Document Literal wrapped

Ce format a été défini par Microsoft pour la plate-forme .Net et il n'existe aucune spécification officielle mais c'est un standard de fait. Ce format reprend le format Document Literal mais le corps contient un élément qui précise le nom de l'opération.

Le tag <body> possède plusieurs caractéristiques en Document/Literal wrapped :

  • le corps du message n'est composé que d'une seule partie
  • cette partie est encapsulée dans un élément dont le nom correspond au nom de l'opération invoquée
  • les éléments des paramètres ne possèdent aucun attribut

Le fichier WSDL

Exemple :
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions targetNamespace="http://axis.test.jmdoudoux.com" 
    xmlns:apachesoap="http://xml.apache.org/xml-soap" 
    xmlns:impl="http://axis.test.jmdoudoux.com" 
    xmlns:intf="http://axis.test.jmdoudoux.com" 
    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
    xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<!--WSDL created by Apache Axis version: 1.3
Built on Oct 05, 2005 (05:23:37 EDT)-->
 <wsdl:types>
  <schema elementFormDefault="qualified" 
      targetNamespace="http://axis.test.jmdoudoux.com" 
      xmlns="http://www.w3.org/2001/XMLSchema">
   <element name="additionner">
    <complexType>
     <sequence>
      <element name="valeur1" type="xsd:int"/>
      <element name="valeur2" type="xsd:int"/>
     </sequence>
    </complexType>
   </element>
   <element name="additionnerResponse">
    <complexType>
     <sequence>
      <element name="additionnerReturn" type="xsd:long"/>
     </sequence>
    </complexType>
   </element>
  </schema>
 </wsdl:types>
   <wsdl:message name="additionnerResponse">
      <wsdl:part element="impl:additionnerResponse" name="parameters"/>
   </wsdl:message>
   <wsdl:message name="additionnerRequest">
      <wsdl:part element="impl:additionner" name="parameters"/>
   </wsdl:message>
   <wsdl:portType name="Calculer">
      <wsdl:operation name="additionner">
         <wsdl:input message="impl:additionnerRequest" name="additionnerRequest"/>
         <wsdl:output message="impl:additionnerResponse" name="additionnerResponse"/>
      </wsdl:operation>
   </wsdl:portType>
   <wsdl:binding name="CalculerSoapBinding" type="impl:Calculer">
      <wsdlsoap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
      <wsdl:operation name="additionner">
         <wsdlsoap:operation soapAction=""/>
         <wsdl:input name="additionnerRequest">
            <wsdlsoap:body use="literal"/>
         </wsdl:input>
         <wsdl:output name="additionnerResponse">
            <wsdlsoap:body use="literal"/>
         </wsdl:output>
      </wsdl:operation>
   </wsdl:binding>
   <wsdl:service name="CalculerService">
      <wsdl:port binding="impl:CalculerSoapBinding" name="Calculer">
         <wsdlsoap:address location="http://localhost:8080/TestWS/services/Calculer"/>
      </wsdl:port>
   </wsdl:service>
</wsdl:definitions>

Descripteur Axis

Exemple :
<service name="Calculer" provider="java:RPC" style="wrapped" use="literal">
  <operation name="additionner" qname="ns1:additionner" 
      returnQName="ns1:additionnerReturn" returnType="xsd:long" 
      soapAction="" xmlns:ns1="http://axis.test.jmdoudoux.com" 
                    xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <parameter qname="ns1:valeur1" type="xsd:int"/>
    <parameter qname="ns1:valeur2" type="xsd:int"/>
  </operation>
  <parameter name="allowedMethods" value="additionner"/>
  <parameter name="typeMappingVersion" value="1.2"/>
  <parameter name="wsdlPortType" value="Calculer"/>
  <parameter name="className" value="com.jmdoudoux.test.axis.Calculer"/>
  <parameter name="wsdlServicePort" value="Calculer"/>
  <parameter name="schemaQualified" value="http://axis.test.jmdoudoux.com"/>
  <parameter name="wsdlTargetNamespace" value="http://axis.test.jmdoudoux.com"/>
  <parameter name="wsdlServiceElement" value="CalculerService"/>
 </service>

La requête SOAP

Exemple :
<?xml version="1.0" encoding="UTF-8" ?> 
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
                  xmlns:q0="http://axis.test.jmdoudoux.com" 
                  xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
                  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <soapenv:Body>
    <q0:additionner>
      <q0:valeur1>20</q0:valeur1> 
      <q0:valeur2>30</q0:valeur2> 
    </q0:additionner>
  </soapenv:Body>
</soapenv:Envelope>

La réponse SOAP

Exemple :
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
                  xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
                  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <soapenv:Body>
    <additionnerResponse xmlns="http://axis.test.jmdoudoux.com">
      <additionnerReturn>50</additionnerReturn> 
    </additionnerResponse>
  </soapenv:Body>
</soapenv:Envelope>

Avantages :

  • le contenu du corps du message est défini par un schéma permettant ainsi sa validation
  • le nom de l'opération est inclus dans la requête SOAP sous la forme d'un tag au nom de l'opération et placé entre le tag <body>et les tags contenant les paramètres.
  • ce format est relativement proche du format RPC/Literal

Inconvénient :

  • il n'est pas possible d'utiliser ce style avec des méthodes surchargées 

 

69.3.6. Le choix du format à utiliser

Les différents formats (style et encodage) des services web ont tous des restrictions d'utilisation qui peuvent engendrer des limitations dans l'écriture des services ou forcer l'utilisation d'un format ou d'un autre.

 

69.3.6.1. L'utilisation de document/literal

Dans ce mode, le nom de l'opération n'est pas fourni dans le message : le mapping pour déterminer l'opération à invoquer repose donc sur les paramètres.

Il n'est donc pas possible d'invoquer le service ci-dessous avec le mode document/literal

Exemple :
public MonService {
  public void maMethode(int x, int y);
  public void maSecondeMethode(int x, int y);
}

 

69.3.6.2. L'utilisation de Document/Literal Wrapped

Il pourrait être tentant de toujours utiliser le mode Document/Literal Wrapped mais ce n'est pas forcément le meilleur choix :

  • ce mode n'est pas supporté par tous les moteurs SOAP
  • il n'est pas possible d'utiliser des opérations surchargées dans un service puisque le mapping de l'opération sur la méthode se fait sur le nom de la méthode. La classe ci-dessous ne peut pas être exposée sous la forme d'un service web invoqué par le mode Document/Literal Wrapped.
Exemple :
public MonService {
  public void maMethode(int x, int y);
  public void maMethode(int x);
}

Remarque : WSDL 2.0 interdit l'utilisation des opérations surchargées.

 

69.3.6.3. L'utilisation de RPC/Literal

Comme le mode Document/Literal ne contient pas le nom de l'opération à invoquer, il y a des cas où il faut utiliser le mode Document/Literal Wrapped ou un des deux modes RPC/Encoded ou RPC/Literal.

Exemple :
public MonService {
  public void maMethode(int x, int y);
  public void maMethode(int x);
  public void maSecondeMethode(int x, int y);
}

L'exemple ci-dessus ne peut pas être invoqué ni en Document/Literal ni en Document/Literal Wrapped.

Comme le mode RPC/encoded n'est pas WS-I Basic Profile compliant, il ne reste que le mode RPC/Literal

 

69.3.6.4. L'utilisation de RPC/Encoded

Le mode RPC/Encoded n'est pas WS-I Basic Profile compliant mais il est parfois nécessaire de l'utiliser. Ce mode est le seul qui puisse prendre en charge un graphe d'objets contenant plusieurs fois la même référence.

Exemple :
<complexType name="MonElement">
    <sequence>
        <element name="nom" type="xsd:string"/>
        <element name="partie1" type="MonElement" xsd:nillable="true"/>
        <element name="partie2" type="MonElement" xsd:nillable="true"/>
    </sequence>
</complexType>

RPC/Encoded utilise l'attribut id pour donner un identifiant à un élément et utilise un attribut href pour y faire référence.

Exemple :
<element1>
    <name>nom1</name>
    <partie1 href="1234"/>
    <partie2 href="1234"/>
</element1>
<element2 id="1234">
    <name>nom2</name>
    <partie1 xsi:nil="true"/>
    <partie2 xsi:nil="true"/>
</element2>

Dans le style Literal, il n'y pas de moyen de faire une référence sur un objet déjà présent dans le graphe : la seule solution c'est de le dupliquer, ce qui va poser des problèmes au consommateur du service.

 

69.4. Des conseils pour la mise en oeuvre

Avant de développer des services web, il faut valider la solution choisie avec un POC (Proof Of Concept) ou un prototype. Lors de ces tests, il est important de vérifier l'interopérabilité notamment si les services web sont consommés par différentes technologies.

Le choix du moteur SOAP est aussi très important notamment vis-à-vis du support des spécifications, des performances, de la documentation, ...

 

69.4.1. Les étapes de la mise en oeuvre

La mise en oeuvre de services web suit plusieurs étapes.

Etape 1 : définition des contrats des services métiers

Cette étape est une phase d'analyse qui va définir les fonctionnalités proposées par chaque service pour répondre aux besoins

Etape 2 : identification des services web

Cette étape doit permettre de définir les contrats techniques des services web à partir des services métiers définis dans l'étape précédente. Un service métier peut être composé d'un ou plusieurs services web.

La réalisation de cette étape doit tenir compte de plusieurs contraintes :

  • Penser forte granularité / faible couplage
  • Ternir compte de contraintes techniques
  • Préférer les services web indépendants du contexte client

L'invocation d'un service est coûteuse notamment à cause du mapping objet/xml et xml/objet réalisé à chaque appel. Cette règle est vraie pour toutes les invocations de fonctionnalités distantes mais encore plus avec les services web. Il est donc préférable de limiter les invocations de méthodes d'un service web en proposant des fonctionnalités à forte granularité. Par exemple, il est préférable de définir une opération qui permet d'obtenir les données d'une entité plutôt que de proposer autant d'opérations que l'entité possède de champs. Ceci permet de réduire le nombre d'invocations du service web et réduit le couplage entre la partie front-end et back-end.

La définition des services web doit tenir compte de contraintes techniques liées aux performances ou à la consommation de ressources. Par exemple, si le temps de traitement d'un service web est long, il faudra prévoir son invocation de façon asynchrone ou si les données retournées sont des binaires de tailles importantes, il faudra envisager d'utiliser le mécanisme de pièces jointes (attachment).

Il est préférable de définir des services web qui soient stateless (ne reposant pas par exemple sur une utilisation de la session http). Ceci permet de déployer les services web dans un cluster où la réplication de session sera inutile.

Etape 3 : écriture des services web

Cette étape est celle du codage proprement dit des services web.

Deux approches sont possibles :

  • écriture du WSDL en premier (contract first) : des outils du moteur Soap sont utilisés pour gérer le code des services web à partir du WSDL. Face à la complexité de la rédaction du WSDL, cette approche n'est pas toujours privilégiée.
  • écriture de la classe et génération du WSDL (code first) : chaque service est implémenté sous la forme d'une ou plusieurs classes et c'est le moteur Soap utilisé qui va générer le WSDL correspondant en se basant sur la description de la classe et des métadonnées.

Etape 4 : déploiement et tests

Les services web doivent être packagés et déployés généralement dans un serveur d'applications ou un conteneur web.

Pour tester les services web, il est possible d'utiliser des outils fournis par l'IDE ou d'utiliser des outils tiers comme SoapUI qui propose de très nombreuses fonctionnalités pour les tests des services web allant de la simple invocation à l'invocation de scénarios complexes et de tests de charges.

Etape 5 : consommation des services web par les applications clientes

Il faut mettre en oeuvre les outils du moteur Soap utilisé par l'application cliente pour générer les classes nécessaires à l'invocation des services web et utiliser ces classes dans l'application. C'est généralement le moment de faire quelques adaptations pour permettre une bonne communication entre le client et le serveur.

 

69.4.2. Quelques recommandations

Afin de maximiser la portabilité d'un service web, il faut essayer de suivre quelques recommandations.

Il ne faut pas se lier à un langage de programmation :

  • n'utiliser que des types communs : int, float, String, Date, ...
  • ne pas utiliser de types spécifiques : Object, DataSet, ...
  • éviter la composition d'objets
  • utiliser un tableau ou des collections typées avec un generic plutôt qu'une collection non typée

Il faut éviter la surchage des méthodes.

Il faut éviter de transformer une classe en service web (notamment en utilisant des annotations) : il est recommandé de définir une interface qui va établir le contrat entre le service et son implémentation. Cette pratique venant de la POO doit aussi s'appliquer pour les services web.

 

69.4.3. Les problèmes liés à SOAP

SOAP est assez complexe et sa mise en oeuvre dépend de l'implémentation de la technologie utilisée côtés consommateur et fournisseur de services web. Il en résulte des problèmes d'interopérabilités alors qu'un des but de SOAP est pourtant de s'en affranchir.

Il existe plusieurs types de problèmes :

Les problèmes liés aux versions de SOAP

Les versions SOAP 1.1 et 1.2 étant incompatibles, cela peut entrainer des problèmes de compatibilité si les implémentations des moteurs SOAP utilisés supportent des versions différentes.

Ceci est notamment le cas si l'implémentation du moteur SOAP est assez ancienne.

Les problèmes liés aux modèles de messages

Un message Soap peut être encodé selon plusieurs modèles : le modèle le plus ancien (RPC) est abandonné au profit du modèle Document.

Cela peut introduire des problèmes d'incompatibilité notamment entre des services web existants et des consommateurs plus récents ou vice-versa.

 

69.5. Les API Java pour les services web

Java propose un ensemble d'API permettant la mise en oeuvre des services web.

API

Rôle

JAXP

API pour le traitement de documents XML : analyse en utilisant SAX ou DOM et transformation en utilisant XSLT.

JAX-RPC

API pour le développement de services web utilisant SOAP avec le style RPC

JAXM

API pour le développement de services utilisant des messages XML orientés documents

JAXR

API pour permettre un accès aux annuaires de référencement de services web

JAXB

API et outils pour automatiser le mapping d'un document XML avec des objets Java

StaX

API pour le traitement de documents XML

SAAJ

API pour permettre la mise en oeuvre des spécifications SOAP with Attachment

JAX-WS

API pour le développement grâce à des annotations de services web utilisant SOAP avec le style Document


L'API de base pour le traitement de document XML avec Java est JAXP. JAXP regroupe un ensemble d'API pour traiter des documents XML avec SAX et DOM et les modifier avec XSLT. Cette API est indépendante de tout parseur. JAXP est détaillée dans le chapitre «Java et XML».

D'autres API sont spécifiques au développement de services web :

  • JAX-RPC (JSR-101) : permet l'appel de procédures distantes en utilisant SOAP (Remote Procedure Call )
  • JAXM (JSR-67) : permet l'envoi de messages (en utilisant SAAJ)
  • JAXR : permet l'accès au service de registre de façon standard (UDDI)
  • SAAJ (SOAP with Attachment API for Java) : permet l'envoi et la réception de messages respectant les normes SOAP et SOAP with Attachment

 

69.5.1. JAX-RPC

JAX-RPC est l'acronyme de Java API for XML-Based Remote Procedure Calls. Cette API permet la mise en oeuvre de services web utilisant SOAP aussi bien côté fournisseur que consommateur : elle permet l'appel de méthodes distantes et la réception de leurs réponses en utilisant SOAP 1.1 et HTTP 1.1.

Cette API a été développée par le JCP sous la JSR 101. Elle propose de masquer un grand nombre de détails de l'utilisation de SOAP notamment en ce qui concerne le codage en XML du message et ainsi de rendre cette API facile à utiliser.

L'utilisation de JAX-RPC est similaire à celle de RMI : le code du client appel les méthodes à partir d'un objet local nommé stub. Cet objet se charge de dialoguer avec le serveur et de coder et décoder les messages SOAP échangés.

Un objet similaire nommé tie permet de réaliser le même type d'opération côté serveur.

La principale différence entre RMI et les services web est que RMI ne peut être utilisé qu'avec Java alors que les services web sont interopérables grâce à XML. Ainsi un client écrit en Java peut utiliser un service web développé avec .Net et vice-versa.

La spécification JAX-RPC définit précisément le mapping entre les types Schema et les types Java.

Type Schema

Type Java

xsd:boolean

boolean

xsd:short

short

xsd:int

int

xsd:long

long

xsd:integer

BigInteger

xsd:float

float

xsd:double

double

xsd:decimal

BigDecimal

xsd:date

java.util.calendar

xsd:time

java.util.calendar

xsd:datetime

java.util.calendar

xsd:base64Binary

byte[]

xsd:hexBinary

byte[]


Les types primitifs qui sont nillable sont mappés sur leurs wrappers Java correspondants.

Les types complexes sont mappés sur des Java beans.

L'API JAX-RPC est regroupée dans plusieurs sous-packages du package javax.xml.rpc

 

69.5.1.1. La mise en oeuvre côté serveur

L'écriture d'un service web avec JAX-RPC requiert plusieurs entités :

  • une interface facultative qui décrit le endpoint
  • une implémentation du endpoint
  • un ou plusieurs fichiers de description et configuration
  • le wdsl du service web

L'utilisation de JAX-RPC côté serveur se fait en plusieurs étapes :

1. Définition de l'interface du service (écrite manuellement ou générée automatiquement par un outil à partir de la description du service (WSDL)).

Exemple :
import java.rmi.Remote;
import java.rmi.RemoteException;

public interface MonWS extends Remote {

  public String getMessage(String nom) throws RemoteException;
}

Cette interface doit étendre l'interface java.rmi.Remote.

Toutes les méthodes définies dans l'interface doivent au minimum déclarer la possibilité de lever une exception de type java.rmi.RemoteException. Chaque méthode peut aussi déclarer d'autres exceptions dans sa définition du moment que ces exceptions héritent de la classe java.lang.Exception.

Les méthodes peuvent sans restriction utiliser des types primitifs et l'objet String pour les paramètres et la valeur de retour. Pour les autres types, il existe dans les spécifications une liste minimale prédéfinie de ceux utilisables.

Une interface particulière peut cependant proposer le support d'autres types. Par exemple, l'implémentation de référence propose le support de la plupart des classes de l'API Collection : ArrayList, HashMap, HashTable, LinkedList, TreeMap, TreeSet, Vector, ... Dans ce cas toutefois, attention à la perte de la portabilité lors de l'utilisation d'une autre implémentation.

2. Ecriture de la classe d'implémentation du service

C'est une simple classe Java qui implémente l'interface définie précédemment et posséde un constructeur sans paramètre : dans l'exemple ci-dessous, celui-ci sera généré lors de la compilation car il n'y a pas d'autre constructeur défini.

Exemple :
public class MonWS_Impl implements MonWS {

  public String getMessage(String nom) {
    return new String("Bonjour " + nom);
  }
}

Il est inutile dans l'implémentation des méthodes de déclarer la levée de l'exception de type RemoteException. C'est lors de l'invocation de la méthode par JAX-RPC que cette exception pourra être levée.

3. Déploiement du service

Le déploiement dépend du moteur Soap utilisé et implique généralement la création d'un fichier de mapping entre l'url et la classe correspondante.

 

69.5.1.2. La mise en oeuvre côté client

JAX-RPC peut aussi être utilisée pour consommer un service web dans un client.

L'invocation de méthodes côté client se fait de manière synchrone avec JAX-RPC : le client fait appel au service et se met en attente jusqu'à la réception de la réponse

Cette invocation du service peut alors être faite selon trois modes :

  • Un stub généré
  • Un proxy dynamique
  • Dynamic Invocation Interface

Un proxy dynamique met en oeuvre un mécanisme proche de celui utilisé par RMI : le client accède à un service distant en utilisant un stub. Le stub sert de proxy : il implémente l'interface du service et se charge des appels au service en utilisant le protocole SOAP lors de l'invocation de ses méthodes.

Ce proxy est généré par un compilateur dédié qui va utiliser le WSDL pour générer le proxy, notamment le portType pour définir l'interface de l'objet et les binding et port pour connaître les paramètres d'appel du service.

Le proxy généré est responsable de la transformation des invocations de méthodes en requêtes Soap et de la transformation des messages Soap en objets selon les indications fournies dans le WSDL. En cas d'erreur, le message Soap de type fault est transformé en une exception.

 

en construction
La suite de cette section sera développée dans une version future de ce document

 

69.5.2. JAXM

JAXM est l'acronyme de Java API for XML Messaging. Cette API permet le développement de services utilisant des messages XML orientés documents.

JAXM a été développée sous la JSR-067.

Les classes de cette API sont regroupées dans le package javax.xml.messaging.

JAXM met en oeuvre SOAP 1.1 et SAAJ

 

69.5.3. JAXR

L'API JAXR (Java API for XML Registries) propose de standardiser les accès aux registres dans lesquels sont recensés les services web. JAXR permet notamment un accès aux registres de type UDDI ou ebXML.

Une implémentation de cette spécification doit être proposée par un fournisseur.

Elle est incluse dans deux packages :

  • javax.xml.registry : classes et interfaces de base (Connection, Query, LifeCycleManager, ...)
  • javax.xml.registry.infomodel : interfaces qui décrivent les informations du modèle stockées dans un registre

Le support de l'accès aux registres de type ebXML est facultatif.

 

69.5.4. SAAJ

L'API SAAJ (SOAP with Attachment API for Java) permet l'envoi et la réception de messages respectant les normes SOAP 1.1 et SOAP with attachments : cette API propose un niveau d'abstraction assez élevé permettant de simplifier l'usage de SOAP.

Les classes de cette API sont regroupées dans le package javax.xml.soap.

Initialement, cette API était incluse dans JAXM. Depuis la version 1.1, elles ont été séparées.

SAAJ propose des classes qui encapsulent les différents éléments d'un message SOAP : SOAPMessage, SOAPPart, SOAPEnvelope, SOAPHeader et SOAPBody.

Tous les échanges de messages avec SOAP utilisent une connexion encapsulée dans la classe SOAPConnection. Cette classe permet la connexion directe entre l'émetteur et le receveur du ou des messages.

 

69.5.5. JAX-WS

JAX-WS (Java API for XML based Web Services) est une nouvelle API, mieux architecturée, qui remplace l'API JAX-RPC 1.1 mais n'est pas compatible avec elle. Il est fortement recommandé d'utiliser le modèle de programmation proposé par JAX-WS notamment pour les nouveaux développements.

Elle propose un modèle de programmation pour produire (côté serveur) ou consommer (côté client) des services web qui communiquent par des messages XML de type SOAP.

Elle a pour but de faciliter et simplifier le développement des services web notamment grâce à l'utilisation des annotations. JAX-WS fournit les spécifications pour le coeur du support des services web de la plate-forme Java SE et Java EE.

JAX-WS a été spécifié par la JSR 224 : Java API for XML-Based Web Services (JAX-WS) 2.0.

JAX-WS permet la mise en oeuvre de plusieurs spécifications :

  • JAX-WS respecte le standard WS-I Basic Profile version 1.1.
  • JAX-WS propose un support pour SOAP 1.1 et 1.2
  • JAX-WS permet le développement de services web orientés RPC (literal) ou orientés documents (literal/encoded/literal wrapped)

JAX-WS repose sur plusieurs autres JSR :

  • JSR 181 (Web Services MetaData for the Java Platform) : propose un ensemble d'annotations qui permettent de définir les services web
  • JSR 109 et JSR 921 (Implementing Enterprise Web Services) : décrit comment déployer, gérer et accéder aux services web par un serveur d'applications
  • JSR 183 (Web Services Message Security APIs) : décrit la sécurisation des messages SOAP

Le fournisseur de l'implémentation de JAX-WS utilise les spécifications de la JSR 921 pour générer les fichiers de configuration et de déploiement à partir des annotations et d'éventuelles métadonnées.

JAX-WS utilise JAXB 2.0 et SAAJ 1.3. JAXB propose une API et des outils pour automatiser le mapping d'un document XML et des objets Java. A partir d'une description du document XML (Schéma XML ou DTD), des classes sont générées pour effectuer automatiquement l'analyse du document ML et le mapping de ce dernier dans des objets Java.

JAX-WS peut être combiné avec d'autres spécifications comme les EJB 3 par exemple.

 

69.5.5.1. La mise en oeuvre de JAX-WS

JAX-WS est une spécification : pour la mettre en oeuvre, il faut utiliser une implémentation.

L'implémentation de référence de JAX-WS est le projet Metro développé par la communauté du projet GlassFish. Il existe d'autres implémentations notamment Axis 2 qui propose son propre modèle de programmation mais aussi un support de JAX-WS.

Le développement d'un service web en Java avec JAX-WS débute par la création d'une classe annotée avec @WebService du package javax.jws. La classe ainsi annotée définit le endpoint du service web.

Le service endpoint interface (SEI) est une interface qui décrit les méthodes du service : celles-ci correspondent aux opérations invocables par un client.

Il est possible de préciser explicitement le SEI en utilisant l'attribut endpointInterface de l'annotation @WebService

 

69.5.5.2. La production de service web avec JAX-WS

Par rapport à JAX-RPC, l'utilisation de JAX-WS est plus simple : un service web peut être basiquement défini en utilisant une classe de type POJO avec des annotations.

La classe d'implémentation du service est donc très simple : un simple POJO avec des annotations. Il n'y a pas besoin d'implémenter une interface particulière de l'API ni de déclarer une exception dans les méthodes.

Avec JAX-WS, la définition d'un service web et de ses opérations se fait en utilisant des annotations soit dans une interface qui décrit le service soit directement dans la classe d'implémentation.

Ni côté client ni côté serveur, le développeur n'a besoin de manipuler le contenu des messages Soap. Ceci est cependant possible pour des besoins très spécifiques.

Les annotations fournissent des métadonnées exploitées par le moteur Soap pour générer le code des traitements sous-jacents. Le développeur est ainsi déchargé de la plomberie et peut se concentrer sur les traitements métiers qui représentent la plus-value du service.

Le développement d'un service web avec JAX-WS requiert plusieurs étapes :

  • coder la classe qui encapsule le service
  • compiler la classe
  • utiliser la commande wsgen pour générer les fichiers requis pour le déploiement (schémas, WSDL, classes, ...)
  • packager le service dans un fichier.war
  • déployer le war dans un conteneur

Pour définir un endpoint avec JAX-WS, il a plusieurs contraintes :

  • la classe qui encapsule le endpoint doit être public, non static, non final, non abstract et être annotée avec @WebService
  • elle doit avoir un constructeur par défaut (sans paramètre)
  • il est recommandé de définir explicitement l'interface du SEI
  • les méthodes exposées par le service web doivent être public, non static, non final et être annotées avec @WebMethod
  • les types des paramètres et de la valeur de retour de ces méthodes doivent être supportés par JAXB
Exemple :
import javax.jws.WebService;
      
import javax.jws.WebMethod;

@WebService
public class MonService {

  @WebMethod
  public String saluer(){
    return "Bonjour";
  }
}

La classe qui encapsule le endpoint du service peut définir des méthodes annotées avec @PostConstruct et @PreDestroy pour définir des traitements liés au cycle de vie du service. Ces méthodes sont invoquées par le conteneur respectivement avant la première utilisation de la classe et avant le retrait du service.

Il faut compiler la classe et utiliser l'outil wsgen pour générer les classes et fichiers requis pour l'exécution du service web.

L'outil wsgen doit être utilisé pour générer les classes utiles à l'exposition du service web : celles-ci concernent essentiellement des classes qui utilisent JAXB pour mapper le contenu du message avec un objet et vice-versa. Il permet aussi de générer le WSDL et les schémas XML des messages.

La syntaxe est de la forme :

wsgen [options] <sei>

<sei> est le nom pleinement qualifié de classe d'implémentation du SEI.

Option

Rôle

-classpath <path>
-cp <path>

Spécifier le classpath

-d <directory>

Préciser le répertoire qui va contenir les classes générées

-help

Afficher l'aide

-keep

Conserver les fichiers générés

-r <directory>

Préciser le répertoire qui va contenir les fichiers de ressources générés (WSDL, ...)

-s <directory>

Préciser le répertoire qui va contenir les fichiers sources générés

-verbose

Activer le mode verbeux

-version

Afficher la version

-wsdl[:protocol]

Demander la génération du WSDL : ce fichier n'est pas utilisé à l'exécution mais il peut être consulté par le développeur pour vérification. Le protocole est facultatif : il permet de préciser la version SOAP qui sera utilisée (les valeurs possibles sont soap1.1 et soap1.2)

-servicename <name>

Définir la valeur de l'attribut name du tag <wsdl:service> lorsque l'option -wsdl est utilisée

-portname <name>

Définir la valeur de l'attribut name du tag <wsdl:port> lorsque l'option -wsdl est utilisée


Une tâche Ant est proposée pour invoquer wsgen par cet outil de build.

Il faut packager le service dans une webapp avec les fichiers compilés.

Il faut déployer le service dans un conteneur web ou un serveur d'applications. Au déploiement, JAX-WS va créer les différentes classes requises pour l'utilisation du service web (celles encapsulant les messages) si celles-ci ne sont pas présentes.

Pour voir le WSDL du service il faut utiliser l'url :

http://localhost:8080/helloservice/hello?wsdl

JAX-WS utilise JAXB-2.0 pour le mapping entre les objets et XML : les objets échangés par les services web peuvent utiliser les annotations de JAXB pour paramétrer finement certains éléments du message SOAP.

Exemple :
package com.jmdoudoux.test.ws;

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;

@WebService() 
public class PersonneWS {

  @WebMethod(operationName = "Saluer")
  public String Saluer(@WebParam(name = "personne") final Personne personne) {
    return "Bonjour " + personne.getNom() + " "+personne.getPrenom();
  } 
}

Exemple :
package com.jmdoudoux.test.ws;

import java.util.Date;

public class Personne {
  
  private String nom;
  private String prenom;
  private Date dateNaiss;

  public Personne() {
    super();
  }

  public Personne(String nom, String prenom, Date dateNaiss) {
    super();
    this.nom = nom;
    this.prenom = prenom;
    this.dateNaiss = dateNaiss;
  }

  public synchronized String getNom() {
    return nom;
  }

  public synchronized void setNom(String nom) {
    this.nom = nom;
  }

  public synchronized String getPrenom() {
    return prenom;
  }

  public synchronized void setPrenom(String prenom) {
    this.prenom = prenom;
  }

  public synchronized Date getDateNaiss() {
    return dateNaiss;
  }

  public synchronized void setDateNaiss(Date dateNaiss) {
    this.dateNaiss = dateNaiss;
  }
}

Le WSDL généré définit l'élément avec un nom dont la première lettre est en minuscule.

Exemple :
<?xml version='1.0' encoding='UTF-8'?>
<!-- Published by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is 
JAX-WS RI 2.1.7-hudson-48-. -->
<xs:schema xmlns:tns="http://ws.test.jmdoudoux.com/" 
              xmlns:xs="http://www.w3.org/2001/XMLSchema" 
              version="1.0" targetNamespace="http://ws.test.jmdoudoux.com/">

  <xs:element name="Saluer" type="tns:Saluer" />

  <xs:element name="SaluerResponse" type="tns:SaluerResponse" />

  <xs:complexType name="Saluer">
    <xs:sequence>
      <xs:element name="personne" type="tns:personne" minOccurs="0" />
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="personne">
    <xs:sequence>
      <xs:element name="dateNaiss" type="xs:dateTime" minOccurs="0" />
      <xs:element name="nom" type="xs:string" minOccurs="0" />
      <xs:element name="prenom" type="xs:string" minOccurs="0" />
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="SaluerResponse">
    <xs:sequence>
      <xs:element name="return" type="xs:string" minOccurs="0" />
      </xs:sequence>
    </xs:complexType>
</xs:schema>

En utilisant l'annotation @XmlType, il est possible de forcer le nom de l'élément généré dans le schéma

Exemple :
package com.jmdoudoux.test.ws;

import java.util.Date;

import javax.xml.bind.annotation.XmlType;

@XmlType(name = "Personne")
public class Personne {
  
  private String nom;
  private String prenom;
  private Date dateNaiss;

   ...
}

Le WSDL généré définit l'élément avec un nom dont la première lettre est en majuscule.

Exemple :
<?xml version='1.0' encoding='UTF-8'?>
<!-- Published by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is 
JAX-WS RI 2.1.7-hudson-48-. -->
<xs:schema xmlns:tns="http://ws.test.jmdoudoux.com/" 
              xmlns:xs="http://www.w3.org/2001/XMLSchema" 
              version="1.0" targetNamespace="http://ws.test.jmdoudoux.com/">

  <xs:element name="Saluer" type="tns:Saluer" />

  <xs:element name="SaluerResponse" type="tns:SaluerResponse" />

  <xs:complexType name="Saluer">
    <xs:sequence>
      <xs:element name="personne" type="tns:Personne" minOccurs="0" />
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="Personne">
    <xs:sequence>
      <xs:element name="dateNaiss" type="xs:dateTime" minOccurs="0" />
      <xs:element name="nom" type="xs:string" minOccurs="0" />
      <xs:element name="prenom" type="xs:string" minOccurs="0" />
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="SaluerResponse">
    <xs:sequence>
      <xs:element name="return" type="xs:string" minOccurs="0" />
    </xs:sequence>
  </xs:complexType>
</xs:schema>

 

69.5.5.3. La consommation de services web avec JAX-WS

Dans la partie cliente, un objet de type proxy est généré pour faciliter l'invocation et la consommation des services web. Les classes de ce proxy sont générées par l'outil wsimport à la demande du développeur à partir du wsdl.

Pour développer un client qui consomme le service web, il y a plusieurs étapes :

  • utiliser l'outil wsimport pour générer les classes du proxy
  • écrire le code des traitements en utilisant le proxy
  • compiler toutes les classes
  • exécuter le client

 

en construction
La suite de cette section sera développée dans une version future de ce document

 

69.5.5.4. Les handlers

Les handlers proposent un mécanisme de traitements particuliers exécutés par le moteur Soap pour permettre d'agir sur les messages de type requête ou réponse. JAX-WS propose deux types de handlers selon la source des données à obtenir ou modifier dans le message :

  • Protocol handler : ce type de handler est dédié à un protocole particulier par exemple Soap. Il permet d'obtenir des informations ou d'en modifier dans toutes les parties du message
  • Logical Handler : ce type de handler est indépendant du protocole utilisé par le message en permettant une modification du corps du message à partir de son contexte JAXB.

Les handlers sont généralement utilisés pour traiter des informations particulières du message Soap

Les handlers pour le protocole SOAP doivent hériter de la classe javax.xml.ws.handler.soap.SOAPHandler. La classe SOAPMessageContext propose des méthodes pour permettre un accès au contenu du message encapsulé dans un objet de type SOAPMessage. Le contenu du message peut alors être manipulé avec l'API SAAJ.

Les logical handlers doivent hériter de la classe javax.xml.ws.handler.LogicalHandler. Ils permettent un accès au contenu du message qui correspond pour un message de type SOAP au body. La classe LogicalMessageContext propose des méthodes pour permettre un accès au contenu du message encapsulé dans un objet de type LogicalMessage.

 

en construction
La suite de cette section sera développée dans une version future de ce document

 

69.5.6. La JSR 181 (Web Services Metadata for the Java Platform)

La JSR 181 propose une spécification pour permettre le développement de services web en utilisant des POJO et des annotations.

La JSR 181 a pour but de définir un modèle de programmation pour faciliter le développement des services web. Ce modèle repose essentiellement sur les annotations : ceci permet de définir les services web sans avoir à connaître les détails de l'implémentation qui sera mise en oeuvre.

Les annotations proposées permettent un contrôle assez fin sur la façon dont un service web va être exposé et invoqué.

La JSR 181 est une spécification dont le but est de fournir un standard pour la déclaration de services web en proposant :

  • Un modèle standard pour le développement de services web en utilisant des annotations
  • De masquer les détails de l'implémentation
  • D'assurer la maintenabilité et l'interopérabilité

Chaque implémentation de cette JSR doit fournir des fonctionnalités pour permettre d'exécuter les classes annotées dans un environnement d'exécution pour les services web.

La mise en oeuvre suit plusieurs étapes :

  • Ecriture de la classe qui contient les fonctionnalités à exposer
  • Annoter la classe ou son interface
  • Exploitation par une implémentation des annotations de la classe pour générer des schémas XML, le WSDL et d'autres fichiers requis pour le déploiement
Exemple :
import javax.jws.WebService;
import javax.jws.WebMethod;

@WebService public class MonService {

  @WebMethod
  public String saluer() {
    return "Bonjour";
  }
}

Il existe plusieurs contraintes dont il faut tenir compte lors de l'implémentation du service. La classe de l'implémentation doit :

  • être public,
  • non final,
  • non abstract,
  • avoir un constructeur par défaut

Par défaut, toutes les méthodes public sont exposées sous la forme d'une opération et ne doivent utiliser que des paramètres respectant ceux définis dans JAX-RPC 1.1. Les méthodes héritées sont aussi exposées sauf celles héritées de la classe Object.

 

69.5.6.1. Les annotations définies

Les annotations sont utilisées dans la classe d'implémentation ou dans l'interface d'un service web.

Toutes les annotations de la JSR 181 sont définies dans le package javax.jws.

Ces annotations sont exploitées au runtime.

Attention : plusieurs implémentations fournissent, en plus des annotations de la JSR 181, des annotations qui leur sont propres. Même si elles sont pratiques, elles limitent la portabilité des services web à s'exécuter dans un autre moteur Soap (exemple : @EnableMTOM, @ServiceProperty, @ServicesProperties dans XFire).

 

69.5.6.2. javax.jws.WebService

L'annotation javax.ws.WebService permet de définir une classe ou une interface comme étant l'interface du endpoint d'un service web.

L'annotation WebService est la seule annotation obligatoire pour développer un service web.

Si l'annotation est utilisée sur l'interface du service web (SEI), il faut aussi l'utiliser sur la classe d'implémentation en précisant l'interface avec l'attribut endpointInterface.

Cette annotation s'utilise sur une classe ou une interface uniquement.

Attribut

Rôle

String name

le nom du service web utilisé dans l'attribut name de l'élément wsdl:portType du WSDL

Par défaut, c'est le nom non qualifié de la classe

String targetNamespace

espace de nommage utilisé dans le WSDL

Par défaut c'est le nom du package

String serviceName

le nom du service utilisé dans l'attribut name de l'élément wsdl:service du WSDL

Par défaut, c'est le nom de la classe suffixée par "Service"

String wsdlLocation

url relative ou absolue du WSDL prédéfini

String endpointInterface

nom pleinement qualifié de l'interface du endpoint (SEI), ce qui permet de séparer l'interface de l'implémentation

String portName

Nom du port du service web utilisé dans l'attribut name de l'élément wsdl:port du WSDL


Exemple :
@WebService(name = "BonjourWS", targetNamespace = "http://www.jmdoudoux.fr/ws/Bonjour")

public class BonjourServiceImpl {

  @WebMethod
  public String saluer() {
    return "Bonjour";
  }
}

 

69.5.6.3. javax.jws.WebMethod

L'annotation javax.ws.WebMethod permet de définir une méthode comme étant une opération d'un service web.

Cette annotation s'utilise sur une méthode uniquement. La méthode sur laquelle cette annotation est appliquée doit être public.

Elle possède plusieurs attributs.

Attribut

Rôle

String operationName

nom utilisé dans l'élément wsdl:operation du message

Par défaut: le nom de la méthode

String action

action associée à l'opération : utilisé comme valeur du paramètre SOAPAction

boolean exclude

booléen qui précise si la méthode doit être exposée ou non dans le service web. Cette propriété n'est utilisable que dans une classe et doit être le seul attribut de l'annotation.

Par défaut : false


L'annotation WebMethod ne peut être utilisée que dans une classe ou une interface annotée avec @WebService.

Les paramètres de la méthode, sa valeur de retour et les exceptions qu'elle peut lever doivent obligatoirement respecter les spécifications relatives à ces entités dans les spécifications JAX-RPC 1.1.

 

69.5.6.4. javax.jws.OneWay

L'annotation javax.ws.OneWay permet de définir une méthode comme étant une opération d'un service web qui ne fournit pas de réponse lors de son invocation. Elle permet une optimisation à l'exécution qui évite d'attendre une réponse qui ne sera pas fournie.

Cette annotation s'utilise sur une méthode uniquement : celle-ci ne doit pas avoir de valeur de retour ou lever une exception puisque dans ce cas, il y a une réponse de type SoapFault.

Cette annotation ne possède aucun attribut.

Exemple :
@WebService
public class MonService {

  @WebMethod
  @Oneway
  public void MonOperation() {
  }
}

 

69.5.6.5. javax.jws.WebParam

L'annotation javax.ws.WebParam permet de configurer comment un paramètre d'une opération sera mappé dans le message SOAP.

Cette annotation s'utilise uniquement sur un paramètre d'une méthode de l'implémentation du service.

Attribut

Rôle

String name

nom du paramètre utilisé dans le WSDL

Par défaut: le nom du paramètre

Mode mode

mode d'utilisation du paramètre. Le type Mode est une énumération qui contient IN, OUT et INOUT

Par défaut : IN

String targetNamespace

précise l'espace de nommage du paramètre dans les messages utilisant le mode document

Par défaut : l'espace de nommage du service web

boolean header

booléen qui indique si la valeur du paramètre est contenue dans l'en-tête de la requête http plutôt que dans le corps

Par défaut : false

String partName

Définit l'attribut name de l'élément <wsdl:part> des messages de type RPC et DOCUMENT/BARE


Cette annotation est pratique pour permettre d'utiliser le même paramètre dans plusieurs opérations d'un service web encodé en document literal.

 

69.5.6.6. javax.jws.WebResult

L'annotation javax.ws.WebResult permet de choisir comment une valeur de retour d'une opération sera mappée dans l'élément wsdl:part message SOAP.

Cette annotation s'utilise sur une méthode uniquement.

Attribut

Rôle

String name

nom de la valeur de retour utilisé dans le WSDL. Avec le style RPC, c'est l'attribut name de l'élément wsdl:part. Avec le style DOCUMENT, c'est le nom de l'élément dans la réponse

Par défaut: return pour RPC et DOCUMENT/WRAPPED et le nom de la méthode suffixé par "Response" pour DOCUMENT/BARE

String targetNamespace

espace de nommage de la valeur de retour dans les messages utilisant le mode document

Par défaut : l'espace de nommage du service web

boolean header

booléen qui indique si la valeur de retour est stockée dans l'en-tête de la requête http plutôt que dans le corps

Par défaut : false

String partName

attribut name de l'élément wsdl:part des messages de type RPC et DOCUMENT/BARE

Par défaut : la valeur de l'attribut name


Cette annotation est pratique pour permettre d'utiliser la même valeur de retour dans plusieurs opérations d'un service web encodé en Document Literal.

 

69.5.6.7. javax.jws.soap.SOAPBinding

L'annotation javax.jws.soap.SOAPBinding permet de déterminer l'encodage du message et de la réponse SOAP.

Cette annotation s'utilise sur une classe, une interface ou une méthode.

Attribut

Rôle

Style style

Définir le style d'encodage du message. Style est une énumération qui contient DOCUMENT et RPC.

Par défaut: DOCUMENT

Use use

Définir le format du message. Use est une énumération qui contient ENCODED et LITERAL.

Par défaut: LITERAL

ParameterStyle parameterStyle

Définir si les paramètres forment le contenu du message ou s'ils sont encapsulés par un tag du nom de l'opération à invoquer. ParameterStyle est une énumération qui contient BARE et WRAPPED. BARE ne peut être utilisé qu'avec le style DOCUMENT

Par défaut: WRAPPED


Exemple :
@WebService
@SOAPBinding(style=Style.DOCUMENT, use=Use.LITERAL, parameterStyle=ParameterStyle.BARE)
public class MonService {

  @WebMethod

  public void MonOperation() {
  }
};

 

69.5.6.8. javax.jws.HandlerChain

 

en construction
La suite de cette section sera développée dans une version future de ce document

 

69.5.6.9. javax.jws.soap.SOAPMessageHandlers

 

en construction
La suite de cette section sera développée dans une version future de ce document

 

69.5.7. La JSR 224 (JAX-WS 2.0 Annotations)

La JSR 224 définit les annotations spécifiques à JAX-WS 2.0.

Toutes ces annotations sont dans le package javax.xml.ws.

 

69.5.7.1. javax.xml.ws.BindingType

L'annotation @BindingType permet de préciser le binding qui sera utilisé pour invoquer le service. Elle s'utilise sur une classe

Attribut

Rôle

value

Identifiant du binding à utiliser. Les valeurs possibles sont : SOAPBinding.SOAP11HTTP_BINDING, SOAPBinding.SOAP12HTTP_BINDING ou HTTPBinding.http_BINDING

La valeur par défaut est SOAP11_HTTP_BINDING

 

69.5.7.2. javax.xml.ws.RequestWrapper

L'annotation @RequestWrapper permet de préciser la classe JAXB de binding qui sera utilisée dans la requête à l'invocation du service. Elle s'utilise sur une méthode

Attribut

Rôle

String className

Préciser le nom pleinement qualifié de la classe qui encapsule la requête (Obligatoire)

String localName

Définir le nom de l'élément dans le schéma qui encapsule la requête.

Par défaut, c'est la valeur de l'attribut operationName de l'annotation WebMethod

String targetNamespace

l'espace de nommage. Par défaut, c'est le targetNamespace du SEI

 

69.5.7.3. javax.xml.ws.ResponseWrapper

L'annotation @ResponseWrapper permet de préciser la classe JAXB de binding qui sera utilisée dans la réponse à l'invocation du service. Elle s'utilise sur une méthode

Attribut

Rôle

String localName

Définir le nom de l'élément dans le schéma qui encapsule la réponse.

Par défaut c'est le nom de l'opération définie par l'annotation @WebMethod concaténé à Response

String targetNamespace

Définir l'espace de nommage. Par défaut, c'est le targetNamespace du SEI

String ClassName

Préciser le nom pleinement qualifié de la classe qui encapsule la réponse (Obligatoire)

 

69.5.7.4. javax.xml.ws.ServiceMode

Cette annotation permet de préciser si le provider va avoir accès uniquement au payload du message (PAYLOAD) ou à l'intégralité du message (MESSAGE).

Elle s'utilise sur une classe qui doit obligatoirement implémenter un Provider.

Attribut

Rôle

Service.Mode value

Indiquer si le provider va avoir accès uniquement au payload du message (PAYLOAD) ou à l'intégralité du message (MESSAGE). La valeur par défaut est PAYLOAD


Exemple :
@ServiceMode(value=Service.Mode.PAYLOAD)
public class MonOperationProvider implements Provider<Source> {
  public Source invoke(Source source)
    throws WebServiceException {
    Source source = null;
    try {
        
      // code du traitement de la requete et generation de la reponse
      
    } catch(Exception e) {
      throw new WebServiceException("Erreur durant les traitements du Provider", e);
    }
    return source;
  }
}

 

69.5.7.5. javax.xml.ws.WebFault

Cette annotation s'utilise sur une classe qui encapsule une exception afin de personnaliser certains éléments de la partie Fault du message Soap. Elle s'utilise sur une exception levée par une opération.

Attribut

Rôle

String name

Le nom de l'élément fault

Cet attribut est obligatoire

String targetNameSpace

Définir l'espace de nommage pour l'élément fault.

String faultBean

Nom pleinement qualifié de la classe qui encapsule l'exception

 

69.5.7.6. javax.xml.ws.WebEndpoint

Cette annotation permet de préciser le portName d'une méthode du SEI.

Elle s'utilise sur une méthode.

Attribut

Rôle

String name

Définir le nom qui va identifier de façon unique l'élément <wsdl:port> du tag <wsdl:service>

 

69.5.7.7. javax.xml.ws.WebServiceclient

 

en construction
La suite de cette section sera développée dans une version future de ce document

 

69.5.7.8. javax.xml.ws.WebServiceProvider

Cette annotation est à utiliser sur une implémentation d'un Provider

Elle s'utilise sur des classes qui héritent de la classe Provider.

Attribut

Rôle

String portName

nom du port du service (élément <wsdl:portName>)

String serviceName

nom du service (élément <wsdl:service>)

String targetNamespace

espace de nommage

String wsdlLocation

chemin du WSDL du service


Exemple :
@WebServiceProvider
public class MonOperationProvider implements Provider<Source> {
  public Source invoke(Source source) throws WebServiceException {
    Source source = null;
    try {
        
      // code du traitement de la requete et generation de la reponse
      
    } catch(Exception e) {
      throw new WebServiceException("Erreur durant les traitements du Provider", e);
    }
    return source;
  }
}

 

69.5.7.9. javax.xml.ws.WebServiceRef

L'annotation WebServiceRef permet de définir une référence sur un service web et éventuellement autorise son injection.

Cette annotation est à utiliser dans un contexte Java EE.

Elle s'utilise sur une classe, une méthode (getter ou setter) ou un champ.

Attribut

Rôle

String name

nom JNDI de la ressource.

Par défaut sur un champ c'est le nom du champ.

Par défaut sur un getter ou un setter, c'est le nom de la propriété

Class type

type de la ressource.

Par défaut sur un champ, c'est le type du champ.

Par défaut sur un getter ou un setter, c'est le type de la propriété

String mappedName

nom spécifique au conteneur sur lequel le service est mappé (non portable)

Class value

classe du service qui doit étendre javax.xml.ws.Service

String wsdlLocation

chemin du WSDL du service

 

69.6. Les implémentations des services web

Il existe de nombreuses implémentations possibles de moteurs SOAP permettant la mise en oeuvre de services web avec Java, notamment plusieurs solutions open source :

  • Intégrées à la plate-forme Java EE 5.0 et Java SE 6.0
  • JWSDP de Sun
  • Axis et Axis 2 du projet Apache
  • XFire
  • CXF du projet Apache
  • JBoss WS
  • Metro du projet GlassFish
  • ...

A cause d'un effort de spécification tardif de JAX-WS, plusieurs implémentations utilisent une approche spécifique pour la mise en oeuvre et le déploiement de services web, ce qui rend le choix d'une de ces solutions délicat. Heureusement, toutes tendent à proposer un support de JAX-WS.

Même si les concepts sous-jacents sont équivalents, quelle que soit l'implémentation utilisée, sa mise en oeuvre est très différente d'une implémentation à l'autre.

De plus, la plupart des solutions historiques sont relativement complexes à mettre en oeuvre car certains points techniques ne sont pas assez masqués par les outils (code à écrire, fichiers de configuration, descripteurs de déploiement, ...). Avec ces solutions, le développeur doit consacrer une part non négligeable de son temps à du code technique pour développer le service web.

JAX-WS propose une solution pour simplifier grandement le développement des services grâce à l'utilisation d'annotations qui évitent d'avoir à écrire du code ou des fichiers pour la plomberie. JAX-WS, en tant que spécification, est implémentée dans plusieurs solutions.

 

69.6.1. Axis 1.0

Axis (Apache eXtensible Interaction System) est un projet open-source du groupe Apache diffusé sous la licence Apache 2.0 qui propose une implémentation d'un moteur de service web implémentant le protocole SOAP : il permet de créer, déployer et consommer des services web.

Son but est de proposer un ensemble d'outils pour faciliter le développement, le déploiement et l'utilisation des services web écrits en java. Axis propose de simplifier au maximum les tâches pour la création et l'utilisation des services web. Il permet notamment de générer automatiquement le fichier WSDL à partir d'une classe Java et le code nécessaire à l'appel du service web.

Pour son utilisation, Axis 1.0 nécessite un J.D.K. 1.3 minimum et un conteneur de servlets (les exemples de cette section utilise Tomcat).

Le site officiel est à l'url http://ws.apache.org/axis/

C'est un projet open source d'implémentation du protocole SOAP. Il est historiquement issu du projet Apache SOAP.

C'est un outil populaire qui de fait est la référence des moteurs de services web Open Source implémentant JAX-RPC en Java : son utilisation est répandue notamment dans des produits open source ou commerciaux.

La version 1.2 diffusé en mai 2005 apporte le support de l'encodage de type Document/Literal pour être compatible avec les spécifications WS-I Basic Profile 1.0 et JAX-RPC 1.1.

La version 1.3 est diffusée en octobre 2005

La version la plus récente est la 1.4, diffusée en avril 2006.

Attention : Axis 1.x n'est plus supporté au profit de Axis 2 qui possède lui aussi des numéros de versions 1.x.

Axis implémente plusieurs spécifications :

  • JSR 101 : Java API for XML-Based RPC (JAX-RPC) 1.1
  • JSR 67 : SOAP with Attachments API for Java Specification (SAAJ) 1.2
  • Java API for XML Registries Specification (JAXR) 1.0

Axis permet donc la mise en oeuvre de :

  • SOAP 1.1 et 1.2
  • WSDL 1.1
  • XML-RPC
  • WS-I Basic Profile 1.1

Attention : Axis 1.0 n'est pas compatible avec

  • JSR 109 Web Services for EE (WS4EE) 1.0
  • JSR 224 Java API for XML-Based Web Services (JAX-WS) 2.0
  • JSR 181 Web Service Metadata for the Java Platform
  • JSR 222 Java Architecture for XML Binding (JAXB) 2.0

Axis génère le document wsdl du service web : pour accéder à ce document il suffit d'ajouter ?wsdl à l'url d'appel du service web.

L'interopérabilité entre Axis et .Net 1.x est assurée tant que les types utilisés se limitent aux primitives, aux chaînes de caractères, aux tableaux des types précédents et aux Java Beans composés uniquement des types précédents ou d'autres Java Beans.

L'interopérabilité entre Axis 1.4 et .Net 2.0 est bien meilleure. Par exemple, la gestion des objets Nullable dans .Net 2.0 est prise en compte (notamment pour les dates et types primitifs) : il n'est donc plus nécessaire d'utiliser une gestion particulière pour ces objets.

Les extensions sont mises en oeuvre au travers du mécanisme de handlers.

 

69.6.1.1. Installation

Il faut télécharger Axis 1.x (par exemple le fichier axis-bin-1_4.zip pour la version 1.4) sur le site et décompresser le contenu de l'archive dans un répertoire du système.

Axis s'utilise en tant qu'application web dans un conteneur web. Pour un environnement de développement avec Tomcat, le plus simple est de copier le répertoire axis contenu dans le sous-répertoire webapps issu de la décompression dans le répertoire des applications web du conteneur (le répertoire webapps pour le serveur Tomcat) et de redémarrer le serveur.

Pour vérifier la bonne installation, il suffit d'ouvrir un navigateur sur l'url de l'application web axis :

 http://localhost:8080/axis/index.phpl

Un clic sur le lien « List » permet de voir les services web qui sont installés.

Un clic sur le lien « Validation » permet d'exécuter une JSP qui fait un état des lieux de la configuration du conteneur et des API nécessaires et optionnelles accessibles.

 

69.6.1.2. La mise en oeuvre côté serveur

Axis 1.x propose deux méthodes pour déployer un service web :

  • le déploiement automatique d'une classe Java dont l'extension est .jws
  • l'utilisation d'un fichier WSDD avec la classe d'implémentation

 

69.6.1.2.1. Mise en oeuvre côté serveur avec JWS

Axis propose une solution pour facilement et automatiquement déployer une classe Java en tant que service web. Il suffit simplement d'écrire la classe, de remplacer l'extension .java en .jws (java web service) et de copier le fichier dans le répertoire de la webapp axis.

Remarque : il ne faut pas compiler le fichier .jws

 

69.6.1.2.2. Mise en oeuvre côté serveur avec un descripteur de déploiement

Cette solution est un peu moins facile à mettre en oeuvre mais elle permet d'avoir un meilleur contrôle sur le déploiement du service web.

Il faut écrire la classe Java qui va contenir les traitements proposés par le service web.

Exemple :
public class MonServiceWebAxis2{

  public String message(String msg){
    return "Bonjour "+msg;
  }
}

Il faut compiler cette classe et mettre le fichier .class dans le répertoire WEB-INF/classes de la webapps axis.

Il faut créer le fichier WSDD qui va contenir la description du service web.

Exemple : le fichier deployMonServiceWebAxis2.wsdd
<deployment xmlns="http://xml.apache.org/axis/wsdd/"
            xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
  <service name="monServiceWebAxis2" provider="java:RPC">
    <parameter name="className" value="MonServiceWebAxis2"/>
    <parameter name="allowedMethods" value="*"/>
  </service>
</deployment>

Il faut ensuite déployer le service web en utilisant l'application AdminClient fournie par Axis.

Résultat :
C:\java\jwsdp-1.1\webapps\axis\WEB-INF\classes>java org.apache.axis.client.Admin
Client deployMonServiceWebAxis2.wsdd
- Processing file deployMonServiceWebAxis2.wsdd
- <Admin>Done processing</Admin>

L'extension wsdd signifie WebService Deployment Descriptor.

C'est un document xml dont le tag racine est deployment.

Les informations relatives au service web sont définies dans le tag service qui possède plusieurs attributs notamment :

  • name :
  • provider :

Plusieurs informations doivent être fournies avec un tag parameter qui possède les attributs name et value :

  • className : le nom pleinement qualifié de la classe d'implémentation du service web
  • allowedMethods : précise les méthodes qui sont exposées. Le caractère étoile permet d'indiquer toutes les méthodes

 

69.6.1.3. Mise en oeuvre côté client

Pour faciliter l'utilisation d'un service web, Axis propose l'outil WSDL2Java qui génère automatiquement à partir d'un document WSDL des classes qui encapsulent l'appel à un service web. Grace à ces classes, l'appel d'un service web par un client ne nécessite que quelques lignes de code.

Résultat :
C:\java\jwsdp-1.1\webapps\axis\WEB-INF\classes>java org.apache.axis.wsdl.WSDL2Ja
va
http://localhost:8080/axis/services/monServiceWebAxis2?wsdl

L'utilisation de l'outil WSDL2Java nécessite une url vers le document WSDL qui décrit le service web. Il génère à partir de ce fichier plusieurs classes dans le package localhost. Ces classes sont utilisées dans le client pour appeler le service web.

Résultat :
C:\java\jwsdp-1.1\webapps\axis\WEB-INF\classes>java org.apache.axis.wsdl.WSDL2Ja
va http://localhost:8080/axis/services/monServiceWebAxis2?wsdl 

Il faut utiliser les classes générées pour appeler le service web.

Exemple :
import localhost.MonServiceWebAxis2; 
import localhost.*;

public class MonServiceWebAxis2Client{

  public static void main(String[] args) throws Exception{
    MonServiceWebAxis2Service locator = new MonServiceWebAxis2ServiceLocator();
    MonServiceWebAxis2 monsw = locator.getmonServiceWebAxis2();
    String s = monsw.message("Jean Michel");
    System.out.println(s);
  }
}

Résultat :
C:\java\jwsdp-1.1\webapps\axis\WEB-INF\classes>javac MonServiceWebAxis2client.java
C:\java\jwsdp-1.1\webapps\axis\WEB-INF\classes>java MonServiceWebAxis2Client

Bonjour Jean Michel

Axis propose une API regroupée dans le package org.apache.axis.client pour faciliter l'appel de services web par un client.

Exemple :
package com.jmdoudoux.test.axis;

import java.rmi.RemoteException;

import javax.xml.namespace.QName;
import javax.xml.rpc.ServiceException;

import org.apache.axis.client.Call;
import org.apache.axis.client.Service;

public class TestCalculerManuel {

  public static void main(String[] args) {
    Service service = new Service();
    Call call;

    try {
      call = (Call) service.createCall();
      String endpoint = "http://localhost:8080/TestWS/services/Calculer";

      call.setTargetEndpointAddress(endpoint);
      call.setOperationName(new QName("additionner"));
      long resultat = (Long) call.invoke(new Object[] { 10, 20 });

      System.out.println("resultat = " + resultat);
    } catch (ServiceException e) {
      e.printStackTrace();
    } catch (RemoteException e) {
      e.printStackTrace();
    }
  }
}

Résultat :
26 déc. 2006 11:22:32 org.apache.axis.utils.JavaUtils isAttachmentSupported
ATTENTION: Unable to find required classes (javax.activation.DataHandler 
and javax.mail.internet.MimeMultipart). Attachment support is disabled.
resultat = 30

La classe Call permet l'invocation d'une méthode d'un service web. Une instance de cette classe est obtenue en utilisant la méthode createCall() d'un objet de type Service.

La méthode setTargetEndpointAddress() permet de préciser l'url du service web à invoquer.

La méthode setOperationName() permet de préciser le nom de l'opération à invoquer.

La méthode invoke() permet de réaliser l'invocation du service web proprement dit.

Pour faciliter cette mise en oeuvre, Axis fournit l'outil wsdl2java qui génère des classes et interfaces à partir du WSDL du service qui sera à invoquer. Ces classes implémentent un proxy qui facilite l'invocation du service web.

Exemple : code client mettant en oeuvre le proxy généré
package com.jmdoudoux.test.axis;

import java.rmi.RemoteException;
import javax.xml.rpc.ServiceException;

public class TestCalculerGenere {

  public static void main(String[] args) {
    CalculerServiceLocator locator = new CalculerServiceLocator();
    long resultat;
    Calculer service;

    try {
      service = locator.getCalculer();
      resultat = service.additionner(10, 20);
      System.out.println("resultat = " + resultat);
    } catch (ServiceException e) {
      e.printStackTrace();
    } catch (RemoteException e) {
      e.printStackTrace();
    }
  }
}

Résultat :
26 déc. 2006 11:22:32 org.apache.axis.utils.JavaUtils isAttachmentSupported
ATTENTION: Unable to find required classes (javax.activation.DataHandler 
and javax.mail.internet.MimeMultipart). Attachment support is disabled.
resultat = 30

Le proxy généré encapsule toute la mécanique d'appel. Un objet de type ServiceLocator facilite l'obtention du endpoint. L'utilisation du proxy rend le code plus simple, plus compréhensible et plus évolutif puisqu'il est généré.

 

69.6.1.4. L'outil TCPMonitor

Cet outil agit comme un proxy qui permet de visualiser les requêtes http échangées entre un client et un serveur.

Résultat :
C:\java\axis-1_4\lib>java -cp ./axis.jar org.apache.axis.utils.tcpmon 1234 localhost 8080

Les paramètres optionnels pouvant être fournis sont :

  • le port écouté sur le client
  • le hostname du serveur
  • le port du serveur

Si aucun paramètre n'est fourni, l'outil affiche une première fenêtre qui permet de saisir les informations requises.

L'outil écoute les requêtes faites sur un port local, les affiche puis ces requêtes sont envoyées au serveur. Les réponses suivent le chemin inverse pour permettre leur affichage.

Cet outil est pratique pour afficher le contenu des requêtes et réponses http échangées lors des invocations.

 

69.6.2. Apache Axis 2

Axis 2 est le successeur du projet Axis : le projet a été complètement réécrit pour proposer une architecture plus modulaire.

Il propose un modèle de déploiement spécifique : les services web peuvent être packagés dans un fichier ayant l'extension.aar (Axis ARchive) ou contenus dans un sous-répertoire du répertoire WEB-INF/services. La configuration se fait dans le fichier META-INF/services.xml

Le runtime d'Axis 2 est une application web qui peut être utilisée dans n'importe quel serveur d'applications Java EE et même un conteneur web comme Apache Tomcat.

Des modules complémentaires permettent d'enrichir le moteur en fonctionnalités notamment le support de certaines spécifications WS-*. Chaque module est packagé dans un fichier avec l'extension .mar

Axis 2 permet de choisir le framework de binding XML/Objets.

 

69.6.3. Xfire

XFire est un projet open source initié par la communauté CodeHaus

L'url du projet est http://xfire.codehaus.org.

Ce projet n'est plus maintenu car il a été repris par le projet CXF d'Apache.

 

69.6.4. Apache CXF

Apache CXF est né de la fusion des projets XFire et Celtix.

L'url du projet est http://cxf.apache.org/

CXF propose un support de plusieurs standards des services web notamment, SOAP 1.1 et 1.2, WSDL 1.1 et 1.2, le WS-I Basic Profile, MTOM, WS-Addressing, WS-Policy, WS-ReliableMessaging, et WS-Security.

CXF utilise une api propriétaire mais implémente aussi les spécifications de JAX-WS. CXF propose plus qu'une implémentation d'un moteur SOAP en proposant un framework complet pour le développement de services

Ses principaux objectifs sont la facilité d'utilisation, les performances, l'extensibilité et l'intégration dans d'autres systèmes. CXF utilise le framework Spring.

CXF est utilisé dans d'autres projets notamment ServiceMix et Mule.

 

69.6.5. JWSDP (Java Web Service Developer Pack)

Le Java Web Services Developer Pack (JWSDP) est un ensemble d'outils et d'API fournis par Sun qui permet de faciliter le développement, le déploiement et le test des services web et des applications web avec Java.

Le JWSDP contient les outils suivants :

  • Apache Tomcat
  • Java WSDP Registry Server (serveur UDDI)
  • Web application development tool
  • Apache Ant
  • wscompile, wsdeploy,
  • ...

La plupart de ces éléments peuvent être installés manuellement séparément. Le JWSDP propose un pack qui les regroupe en une seule installation et propose en plus des outils spécifiquement dédiés au développement de services web.

Le JWSDP contient les API particulières suivantes :

  • Java XML Pack : Java API for XML Processing (JAXP), Java API for XML-based RPC (JAX-RPC), Java API for XML Messaging (JAXM), Java API for XML Registries (JAXR)
  • Java Architecture for XML Binbing (JAXB)
  • Java Secure Socket (JSSE)
  • SOAP with Attachments API for Java (SAAJ)

JWSDP fournit aussi toutes les APIs nécessaires aux développements d'applications Web notamment les API Servlet/JSP, JSTL et JSF.

Remarque : le projet GlassFish remplace le JWSDP.

 

69.6.5.1. L'installation du JWSDP 1.1

Pour pouvoir l'utiliser, il faut au minimum un jdk 1.3.1. Il faut télécharger sur le site de Sun le fichier jwsdp-1_1-windows-i586.exe et l'exécuter.

Un assistant guide l'installation :

  • Cliquer sur "Suivant".
  • Lire le contrat de licence, sélectionner "Approve" et cliquer sur "Suivant".
  • Sélectionner le JDK à utiliser et cliquer sur "Suivant"
  • Dans le cas de l'utilisation d'un proxy, il faut renseigner les informations le concernant. Cliquer sur "Suivant".
  • Sélectionner le répertoire d'installation et cliquer sur "Suivant".
  • Sélectionner le type d'installation et cliquer sur "Suivant".
  • Il faut saisir un nom d'utilisation qui sera l'administrateur et son mot de passe et cliquer sur "Suivant".
  • L'assistant affiche un récapitulatif des options choisies. Cliquer sur "Suivant".
  • Cliquer sur "Suivant".
  • Cliquer sur "Suivant".
  • Cliquer sur "Fin".

 

69.6.5.2. L'exécution du serveur

L'installation a créé une entrée dans le menu "Démarrer/Programmes".

Pour lancer le serveur d'applications Tomcat, il faut utiliser l'option Start Tomcat.

Attention, les ports 8080 et 8081 ne doivent pas être occupés par un autre serveur.

Pour accéder à la console d'administration, il faut lancer un navigateur sur l'url http://localhost:8081/admin. Si la page ne s'affiche pas, il faut aller voir dans le fichier catalina.out contenu dans le répertoire logs où a été installé le JWSDP.

Il faut saisir le nom de l'utilisateur et le mot de passe défini lors de l'installation de JWSDP.

Cette console permet de modifier les paramètres du JWSDP.

 

69.6.5.3. L'exécution d'un des exemples

Il faut créer un fichier build.properties dans le répertoire home (c:\document and settings\user_name) qui contient :

username=
password=

Il faut s'assurer que le chemin C:\java\jwsdp-1_0_01\bin est en premier dans le classpath surtout si une autre version de Ant est déjà installée sur la machine

Il faut lancer Tomcat puis suivre les étapes proposées ci-dessous :

Résultat :
C:\java\jwsdp-1_0_01\docs\tutorial\examples\jaxrpc\hello>dir
Le volume dans le lecteur C s'appelle SYSTEM
Le numéro de série du volume est 18AE-3A71
Répertoire de C:\java\jwsdp-1_0_01\docs\tutorial\examples\jaxrpc\hello
03/01/2003  13:37       <DIR>          .
03/01/2003  13:37       <DIR>          ..
01/08/2002  14:16                  309 build.properties
01/08/2002  14:17                  496 build.xml
01/08/2002  14:17                  222 config.xml
01/08/2002  14:16                2 342 HelloClient.java
01/08/2002  14:17                1 999 HelloIF.java
01/08/2002  14:16                1 995 HelloImpl.java
01/08/2002  14:17                  545 jaxrpc-ri.xml
01/08/2002  14:17                  421 web.xml
               8 fichier(s)            8 329 octets
               2 Rép(s)     490 983 424 octets libres
C:\java\jwsdp-1_0_01\docs\tutorial\examples\jaxrpc\hello>ant compile-server
Buildfile: build.xml
prepare:
     [echo] Creating the required directories....
    [mkdir] Created dir: C:\java\jwsdp-1_0_01\docs\tutorial\examples\jaxrpc\hell
o\build\client\hello
    [mkdir] Created dir: C:\java\jwsdp-1_0_01\docs\tutorial\examples\jaxrpc\hell
o\build\server\hello
    [mkdir] Created dir: C:\java\jwsdp-1_0_01\docs\tutorial\examples\jaxrpc\hell
o\build\shared\hello
    [mkdir] Created dir: C:\java\jwsdp-1_0_01\docs\tutorial\examples\jaxrpc\hell
o\build\wsdeploy-generated
    [mkdir] Created dir: C:\java\jwsdp-1_0_01\docs\tutorial\examples\jaxrpc\hell
o\dist
    [mkdir] Created dir: C:\java\jwsdp-1_0_01\docs\tutorial\examples\jaxrpc\hell
o\build\WEB-INF\classes\hello
compile-server:
     [echo] Compiling the server-side source code....
    [javac] Compiling 2 source files to C:\java\jwsdp-1_0_01\docs\tutorial\examp
les\jaxrpc\hello\build\shared
BUILD SUCCESSFUL
Total time: 7 seconds
C:\java\jwsdp-1_0_01\docs\tutorial\examples\jaxrpc\hello>ant setup-web-inf
Buildfile: build.xml
setup-web-inf:
     [echo] Setting up build/WEB-INF....
   [delete] Deleting directory C:\java\jwsdp-1_0_01\docs\tutorial\examples\jaxrp
c\hello\build\WEB-INF
     [copy] Copying 2 files to C:\java\jwsdp-1_0_01\docs\tutorial\examples\jaxrp
c\hello\build\WEB-INF\classes\hello
     [copy] Copying 1 file to C:\java\jwsdp-1_0_01\docs\tutorial\examples\jaxrpc
\hello\build\WEB-INF
     [copy] Copying 1 file to C:\java\jwsdp-1_0_01\docs\tutorial\examples\jaxrpc
\hello\build\WEB-INF
BUILD SUCCESSFUL
Total time: 2 seconds
C:\java\jwsdp-1_0_01\docs\tutorial\examples\jaxrpc\hello>ant package
Buildfile: build.xml
package:
     [echo] Packaging the WAR....
      [jar] Building jar: C:\java\jwsdp-1_0_01\docs\tutorial\examples\jaxrpc\hel
lo\dist\hello-portable.war
BUILD SUCCESSFUL
Total time: 2 seconds
C:\java\jwsdp-1_0_01\docs\tutorial\examples\jaxrpc\hello>ant process-war
Buildfile: build.xml
set-ws-scripts:
process-war:
     [echo] Running wsdeploy....
     [exec] info: created temporary directory: C:\java\jwsdp-1_0_01\docs\tutoria
l\examples\jaxrpc\hello\build\wsdeploy-generated\jaxrpc-deploy-b5e49c
     [exec] info: processing endpoint: MyHello
     [exec] Note: sun.tools.javac.Main has been deprecated.
     [exec] 1 warning
     [exec] info: created output war file: C:\java\jwsdp-1_0_01\docs\tutorial\ex
amples\jaxrpc\hello\dist\hello-jaxrpc.war
     [exec] info: removed temporary directory: C:\java\jwsdp-1_0_01\docs\tutoria
l\examples\jaxrpc\hello\build\wsdeploy-generated\jaxrpc-deploy-b5e49c
BUILD SUCCESSFUL
Total time: 15 seconds
C:\java\jwsdp-1_0_01\docs\tutorial\examples\jaxrpc\hello>ant deploy
Buildfile: build.xml
deploy:
   [deploy] OK - Installed application at context path /hello-jaxrpc
   [deploy]
BUILD SUCCESSFUL
Total time: 7 seconds
C:\java\jwsdp-1_0_01\docs\tutorial\examples\jaxrpc\hello>ant generate-stubs
Buildfile: build.xml
set-ws-scripts:
prepare:
     [echo] Creating the required directories....
generate-stubs:
     [echo] Running wscompile....
     [exec] Note: sun.tools.javac.Main has been deprecated.
     [exec] 1 warning
BUILD SUCCESSFUL
Total time: 14 seconds
C:\java\jwsdp-1_0_01\docs\tutorial\examples\jaxrpc\hello>ant compile-client
Buildfile: build.xml
prepare:
     [echo] Creating the required directories....
compile-client:
     [echo] Compiling the client source code....
    [javac] Compiling 1 source file to C:\java\jwsdp-1_0_01\docs\tutorial\exampl
es\jaxrpc\hello\build\client
BUILD SUCCESSFUL
Total time: 4 seconds
C:\java\jwsdp-1_0_01\docs\tutorial\examples\jaxrpc\hello>ant jar-client
Buildfile: build.xml
jar-client:
     [echo] Building the client JAR  file....
      [jar] Building jar: C:\java\jwsdp-1_0_01\docs\tutorial\examples\jaxrpc\hel
lo\dist\hello-client.jar
BUILD SUCCESSFUL
Total time: 2 seconds
C:\java\jwsdp-1_0_01\docs\tutorial\examples\jaxrpc\hello>ant run
Buildfile: build.xml
run:
     [echo] Running the hello.HelloClient program....
     [java] Hello Duke!
BUILD SUCCESSFUL
Total time: 5 seconds

C:\java\jwsdp-1_0_01\docs\tutorial\examples\jaxrpc\hello>

 

69.6.6. Java EE 5

Java EE 5 utilise une nouvelle API pour le développement de services web : JAX-WS (Java API for XML Web Services).

 

69.6.7. Java SE 6

Java SE 6 fournit en standard une implémentation de JAX-WS 2.0 permettant ainsi de consommer mais aussi de produire des services web uniquement avec la plate-forme SE.

L'écriture et le déploiement d'un service web suit plusieurs étapes.

Il faut écrire la classe du service web en utilisant les annotations de JAX-WS.

Exemple :
package com.jmdoudoux.test.ws;

import javax.jws.WebService;

@WebService
public class TestWS {
        
  public String Saluer(final String nom) {
    return "Bonjour " + nom;
  }
}

La classe javax.xml.ws.Endpoint encapsule le endpoint d'un service web permettant ainsi son accès.

La méthode publish() permet de publier un endpoint associé à l'url fournie en paramètre.

Exemple :
package com.jmdoudoux.test.ws;

import javax.xml.ws.Endpoint;

public class Main {

  public static void main(String[] args) {

    System.out.println("Lancement du serveur web");
               
    Endpoint.publish("http://localhost:8080/ws/TestWS", new TestWS());
  }
}

Il faut compiler la classe.

Il faut ensuite utiliser l'outil wsgen pour générer les classes JAXB qui vont mapper les requêtes et réponses des messages Soap.

Résultat :
C:\eclipse35\workspace\TestJava6\bin>wsgen -cp . -d ../src com.jmdoudoux.test.ws.TestWS

Dans l'exemple, deux classes sont générées dans le package com.jmdoudoux.test.ws.jaxws :

  • Saluer : pour encapsuler la requête
  • SaluerResponse : pour encapsuler la réponse

Il faut alors exécuter la classe Main : un serveur web minimaliste est lancé et le service web y est déployé.

Attention, l'environnement d'exécution doit être un JDK.

Il suffit alors d'ouvrir l'url http://localhost:8080/ws/TestWS?wsdl dans un navigateur

Le navigateur affiche alors le contenu du WSDL qui décrit le service web.

Le service web peut alors être consommé par un client, tant que l'application est en cours d'exécution.

Exemple : Le message Soap de la requête
<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ws="http://ws.test.jmdoudoux.com/">
   <soapenv:Header/>
   <soapenv:Body>
      <ws:Saluer>
         <arg0>JM</arg0>
      </ws:Saluer>
   </soapenv:Body>
</soapenv:Envelope>

Exemple : Le message Soap en réponse
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
   <S:Body>
      <ns2:SaluerResponse xmlns:ns2="http://ws.test.jmdoudoux.com/">
         <return>Bonjour JM</return>
      </ns2:SaluerResponse>
   </S:Body>
</S:Envelope>

 

69.6.8. Le projet Metro et WSIT

Le projet Metro est une pile pour services web utilisée dans le serveur d'applications GlassFish V2 et V3.

Metro est l'implémentation de référence de JAX-WS.

Metro est livré avec GlassFish mais il est possible de l'utiliser dans d'autres serveurs d'applications ou conteneurs web, par exemple Tomcat. Dans ce dernier cas, il faut ajouter les bibliothèques de Metro et JAXB.

Metro est composé de deux éléments :

  • Une implémentation de JAX-WS pour le support des services web
  • Le projet Tango qui est une implémentation de certaines spécifications WS-*

Le projet Tango est une implémentation open source des spécifications Reliability, Security et Transaction des spécifications WS-*, ce qui facilite l'interopérabilité avec le framework WCF (Windows Communication Foundation) de Microsoft .Net versions 3.0 et ultérieures.

WSIT (Web Service Interoperability) est un projet commun entre Sun et Microsoft pour garantir l'intéropérabilité des piles de services web des plate-formes Java et .Net (avec le Windows Communication Framework).

Cette interopérabilité est assurée car Metro et WCF supportent tous les deux plusieurs spécifications WS-* :

  • WS-Addressing
  • WS-Policy
  • WS-Security
  • WS-Transaction
  • WS-Reliable Messaging
  • WS-Trust
  • WS-SecureConversation

La mise en oeuvre de ces spécifications via WSIT repose sur une configuration dans un fichier XML. Le contenu de ce fichier peut être fastidieux à créer ou à modifier : Netbeans propose des assistants graphiques qui facilitent grandement leur mise en oeuvre.

 

69.7. Inclure des pièces jointes dans SOAP

Pour inclure des données binaires importantes dans un message SOAP, il faut utiliser le mécanisme des pièces jointes (attachment).

Malheureusement, ce mécanisme est implémenté par plusieurs standards :

  • SOAP With Attachments : définis par le W3C dans la version 1.1 de SOAP
  • XOP/MTOM : définis par le W3C dans la version 1.2 de SOAP

MTOM devient le standard utilisé par Java (JAX-WS) et .Net (WSE 3.0)

 

69.8. WS-I

Les nombreuses spécifications concernant les services web sont fréquemment incomplètes ou peu claires : il en résulte plusieurs incompatibilités lors de leur mise en oeuvre.

Le consortium WS-I (Web Service Interoperability) http://www.ws-i.org/ a été créé pour définir des profiles qui sont des recommandations dont le but est de faciliter l'interopérabilité des services web entre plateformes, systèmes d'exploitation et langages pour promouvoir ces normes.

Le WS-I a définit plusieurs spécifications :

  • WS-I Basic Profile
  • WS-I Basic Security Profile
  • Simple Soap Binding Profile
  • ...

Le site web est à l'url : www.ws-i.org

 

69.8.1. WS-I Basic Profile

WS-I Basic Profile est un ensemble de recommandations dont le but est d'améliorer l'interopérabilité entre les différents moteurs SOAP.

 

en construction
La suite de cette section sera développée dans une version future de ce document

 

69.9. Les autres spécifications

Les spécifications SOAP et WSDL permettent de réaliser des échanges de messages basiques. L'accroissement de l'utilisation des services web a fait émerger la nécessité de fonctionnalités supplémentaires telles que la gestion de la sécurité, des transactions, de la fiabilité des messages, ...

Les spécifications désignées sous l'acronyme WS-* concernent les spécifications de seconde génération des services web (elles étendent les spécifications de la première génération de spécifications constituée par SOAP, WSDL, UDDI). L'abréviation WS-* est communément utilisée car la majorité de ces spécifications commence par WS-.

De nombreuses autres spécifications sont en cours d'élaboration et de tentatives de standardisation ou de reconnaissance par le marché.

Fréquemment ces spécifications sont complémentaires ou dépendantes voire même dans quelques cas concurrentes car elles sont soutenues par des acteurs du marché ou des organismes de standardisation différents. Il est généralement nécessaire d'utiliser plusieurs de ces spécifications pour permettre de répondre aux besoins notamment en terme de sécurité, fiabilité, ...

Il est aussi très important de tenir compte de la maturité d'une spécification avant de la mettre en oeuvre.

Ces spécifications permettent de mettre en oeuvre des scénarios complexes impliquant l'utilisation de services web.

Toutes ces spécifications requièrent l'utilisation de SOAP.

 

en construction
La suite de cette section sera développée dans une version future de ce document

 


Développons en Java v 2.20   Copyright (C) 1999-2021 Jean-Michel DOUDOUX.   
[ Précédent ] [ Sommaire ] [ Suivant ] [ Télécharger ]      [ Accueil ] [ Commentez ]