Création d’un webservice

Pré-requis

Avant de lire cet article, il est nécessaire d’avoir effectué l’installation de l’usine de développement sous LinuxWindows ou Mac OS.

Introduction

Un web-service est une fonction, ou une librairie de fonctions mises à disposition par un serveur Web.

Les web-service peuvent être schématisés par une approche client-server. Le web-service qui délivre la WSDL (WSDL est une grammaire XML permettant de décrire un Service Web. Un fichier .wsdl contient les prototypes des fonctions mises à disposition) sera appelé Server (contact-manager-ws-server) et le projet consommant un web-service sera appelé Client (contact-manager-ws-client).

D’un point de vue pratique, il s’agit d’un échange de fichiers XML, transporté par le protocole HTTP. L’application cliente encode dans un fichier XML, la fonction qu’elle désire appeler, ainsi que les paramètres. Ce fichier est envoyé au serveur. Le serveur le décode, exécute le traitement demandé, encode le résultat dans un fichier XML qui est renvoyé au client.

Le socle met à notre disposition deux archétypes de projets maven pour implémenter des web-services :

  • l’archétype scub-foundation-archetype-ws-server permet de créer un web-service. Les projets qui l’implémentent proposeront le web-service, effectueront le traitement demandé et renverront la réponse.
  • l’archétype scub-foundation-archetype-ws-client permet de consommer un web-service. Les projets qui l’implémentent envoie leurs demandes à la partie serveur et attendent une réponse.
Les archétypes relatifs aux web-services mis à dispositions par le socle ne jouent que le rôle de « connecteur ». Ils permettent de développer rapidement des web-services à partir de services SOA. Le schéma suivant illustre cette logique dans le cas du projet exemple contact-manager.

Présentation de Spring Web Services

Les web-services que nous allons développer dans ce tutoriel vont s’appuyer principalement sur l’API Spring Web Services. Spring Web Service est une API qui respecte une approche Contract-First, c’est-à-dire que la base du développement d’un web-service se situe dans la réalisation du schéma XML définissant les échanges entre le serveur et le client. Pour dispenser les développeurs de l’écriture de fichier xml, nous utilisons un plugin Maven associé à la librairie JAXB2 qui nous permet une abstraction totale à la fois des fichiers XML mais également de la gestion de la marshalling/unmarshalling.

Modèle de projet

Les projets permettant la création de web-services respectent la structure standard de répertoire de Maven. On retrouve donc :

  • le répertoire src qui regroupe les sources java et les ressources du projet
  • le répertoire target qui contient tous les éléments générés
  • le fichier pom.xml qui contient la description détaillée du projet

Le socle ajoute un répertoire conf qui va aider à gérer les configurations différentes suivant l’environnement (dev, test, prod-test, prod).

Le projet WebService-Server

Le répertoire src/main/java

Ce répertoire est destiné à accueillir les ressources nécessaires à l’application. Cela permet par exemple de déclarer tous les messages localisés (FR, EN, etc…) utilisés par l’application. Les fichiers de ce répertoire vont être répartis en quatre packages distincts :

  • Un package dto : il contient toutes les classes annotées des DTO. Ces classes sont utilisées pour le transfert des informations dans les échanges du web-service.
  • Un package endpoint : il contient la classe de endpoint, c’est à dire la classe qui fait les appels aux services (dans notre cas à l’interface de services contact-manager-core-interfaces) afin d’effectuer le traitement nécessaire et qui retourne une réponse.
  • Un package message : il contient les classes définissant les messages de requête du web-service
  • Un package namespace : il contient une unique classe définissant les namespaces des xsd générés via ce projet.

Le répertoire conf

Ce répertoire contient cinq sous-répertoires contenant les fichiers de configuration propres aux différents environnements dans lesquels l’application peut être utilisée:

  • Le répertoire common contient les fichiers de configuration communs à tous les environnements de projet.
  • Le répertoire dev contient les fichiers de configuration propres à l’environnement de développement c’est à dire quand l’application est en cours de développement par les développeurs.
  • Le répertoire prod contient les fichiers de configuration propres à l’environnement de production du projet c’est à dire quand l’application est en production chez le client.
  • Le répertoire prod-test contenant les fichiers de configuration propres à l’environnement de test en mode production c’est à dire quand le projet est en cours de test chez le client.
  • Le répertoire test contenant les fichiers de configuration propres à l’environnement de test.
De façon plus spécifique, nous allons nous intéresser à certains des fichiers contenus dans ces répertoires et qui sont nécessaire la configuration de la partie serveur du web-service.
  • Le fichier dozer-bean-mapping.xml du répertoire conf/common/ressources. Ce fichier va contenir la configuration dozer utilisée pour mapper deux objets l’un en l’autre.
  • Le fichier rmiServiceImporterSpecContext.xml du répertoire conf/dev/ressources. Il permet d’importer des services propres à un environnement particulier (ici l’environnement de développement).
  • Le fichier services/servlet.xml du répertoire conf/dev/ressources. Il paramètre le serveur (par exemple, détermine quels packages contiennent des classes annotées et doivent donc être scannés)

Le projet WebService-Client

Le répertoire src/main/java

Ce répertoire est destiné à accueillir les ressources nécessaires à l’application. Cela permet par exemple de déclarer tous les messages localisés (FR, EN, etc…) utilisés par l’application. Il reçoit également les fichiers xsd et wsdl générés. Les fichiers de ce répertoire vont être répartis en deux packages distincts :

  • Un package consumer : il contient toutes les classes définissant les services de consommation du web-service (ces classes implémentent les interfaces de services de contact-manager-ws-interfaces).
  • Un package message : il contient les classes request et response du web-service. Elles sont générées à partir du fichier wsdl précisé dans la configuration.

Le répertoire conf

Comme dans le cas de la partie serveur, ce répertoire va contenir les fichiers de configuration propres aux différents environnements de développement.

Le répertoire conf contient de nombreux fichiers. Tous ne nous sont pas utiles, nous allons donc voir ceux qui vont nous permettre de configurer la partie client du web-service.

De façon plus spécifique, nous allons nous intéresser à certains des fichiers contenus dans ces répertoires et qui sont nécessaire la configuration de la partie cliente du web-service.

  • Le fichier applicationContext.xml du répertoire conf/common/ressources. Il permet de mettre en place le marshalling/unmarshalling (c’est à dire la transformation d’une information complexe en un format plus simple permettant ainsi leur échange entre applications).

Création d’un web-service

Définition des messages

La première étape est donc de définir le contenu des échanges entre notre web-service et ses consommateurs. Dans ce tutoriel, nous allons voir comment transformer les services du noyau contact-manager en web-service. Nous allons donc définir les requêtes et les réponses mises en jeu dans les échanges.

Un service web n’offrant pas forcement la même granularité qu’un service noyau, tous les services proposés par un noyau n’ont pas forcément besoin d’être retranscris en web-service.

Prenons l’interface des services ContactService (dans contact-manager-core-interfaces) :

package org.scub.foundation.contact.manager.core.service.interfaces;
 
import java.util.List;
 
import org.scub.foundation.contact.manager.core.dto.ContactCriteresRechercheDto;
import org.scub.foundation.contact.manager.core.dto.ContactDto;
import org.scub.foundation.framework.base.paging.RemotePagingCriteriasDto;
import org.scub.foundation.framework.base.paging.RemotePagingResultsDto;
 
/**
 * Services permettant de manipuler les contacts du gestionnaire.
 * @author Adrien HAUTOT (adrien.hautot@scub.net)
 */
public interface ContactService {
 
    /**
     * Sauvegarde un contact.
     * @param contact le contact à sauvegarder
     * @return le contact sauvegardé
     */
    ContactDto ajouterOuModifierContact(ContactDto contact);
 
    /**
     * Supprime un contact.
     * @param idContact l'identifiant du contact à supprimer
     */
    void deleteContact(Long idContact);
 
    /**
     * Récupère le contact correspondant à l'identifiant passé en paramètre.
     * @param id identifiant du contact
     * @return le contact trouvé.
     */
    ContactDto getContactById(Long id);
 
    /**
     * Récupère tous les contacts.
     * @return la liste des contacts.
     */
    List getAllContacts();
 
    /**
     * Service de recherche de contacts par critères.
     * @param criteria les critères pour la recherche du contact
     * @return la liste des contacts qui correspondent aux critères passés en paramètre.
     */
    RemotePagingResultsDto getContactsByCriteria(RemotePagingCriteriasDto criteria);
}

Cette classe propose tout un ensemble de méthodes permettant de créer, rechercher, modifier et supprimer un contact. Toutes ces méthodes n’ont pas forcément besoin d’être proposés sous forme de web-service. Par exemple, le service getContactsByCriteria qui à besoin qu’on lui spécifie un critère de recherche pourrait très bien ne pas être adapté en web-service.

Comme pour un service RMI classique, nous allons avoir besoin de définir une interface pour notre web-service. C’est le projet contact-manager-ws-client-interface qui va contenir les interfaces de notre web-service. Voici l’interface web-service du noyau RMI ci-dessus présent dans le package org.scub.foundation.contact.manager.ws.client.interfaces de ce projet :

package org.scub.foundation.contact.manager.ws.client.interfaces;
 
import java.util.List;
 
import org.scub.foundation.contact.manager.ws.client.dto.ContactCriteresRechercheDto;
import org.scub.foundation.contact.manager.ws.client.dto.ContactDto;
 
/**
 * Interface du service de consommation du web service contactService.
 * @author Arnaud Brochain (arnaud.brochain@scub.net)
 */
public interface ContactServiceConsumer {
 
	/**
	 * Appel du web service addOrUpdateContact.
	 * @return le contactDto modifié
	 * @param contact le contactDto à modifié
	 */
	ContactDto addOrUpdateContact(ContactDto contact);
 
	/**
	 * Appel du web service deleteContact.
	 * @param idContact l'identifiant du contact à supprimer
	 */
	void deleteContact(Long idContact);
 
	/**
	 * Appel du web service getContactbyId.
	 * @return l'objet contactDto
	 * @param idContact l'identifiant du contact recherché
	 */
	ContactDto getContactById(Long idContact);
 
	/**
	 * Appel du web service getAllContacts.
	 * @return la liste des contactDto
	 */
	List getAllContact();
}

Pour chacun de ces web-services, nous allons devoir définir deux classes correspondants aux messages XML de la requête et à celui de la réponse. Ces classes devront être placées au sein du projet web service serveur, dans le cas de notre projet exemple ce sera dans le projet contact-manager-ws-service. Comme nous avons quatre web-services, il va falloir définir sept classes, le web-service deleteContact n’ayant pas de réponses. Ces classes vont devoir respectées des règles de nommages strictes. Le nom de la classe d’une requête devra être suffixé de Request et le nom de la classe d’une réponse le sera par Response, cette contrainte permettant l’automatisation des étapes de sérialisation/dé-sérialisation et offrant une cohérence globale de la description des messages échangés. Voici les classes de messages correspondants aux requêtes et aux réponses du web-service AddOrUpdateContact.

La classe AddOrUpdateContactRequest :

package org.scub.foundation.contact.manager.ws.message;
 
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
 
import org.scub.foundation.contact.manager.ws.dto.ContactWsDto;
import org.scub.foundation.contact.manager.ws.namespace.Namespace;
 
/**
 * Classe définissant le message de requête du web-service AddOrUpdateContact.
 * @author Arnaud Brochain (arnaud.brochain@scub.net)
 */
@XmlRootElement(namespace = Namespace.CONTACT_MANAGER_NAMESPACE, name = "AddOrUpdateContactRequest")
@XmlType(name = "")
@XmlAccessorType(XmlAccessType.FIELD)
public class AddOrUpdateContactRequest {
 
	/**
	 * Contact à ajouter ou modifier.
	 */
	@XmlElement(required = true)
	private ContactWsDto contact;
 
	/**Get contact.
	 * @return the contact
	 */
	public ContactWsDto getContact() {
		return contact;
	}
 
	/**Set contact.
	 * @param contact the contact to set
	 */
	public void setContact(ContactWsDto contact) {
		this.contact = contact;
	}
}

La classe AddOrUpdateContactResponse :

package org.scub.foundation.contact.manager.ws.message;
 
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
 
import org.scub.foundation.contact.manager.ws.dto.ContactWsDto;
import org.scub.foundation.contact.manager.ws.namespace.Namespace;
 
/**
 * Classe définissant le message de réponse du web-service AddOrUpdateContact.
 * @author Arnaud Brochain (arnaud.brochain@scub.net)
 */
@XmlRootElement(namespace = Namespace.CONTACT_MANAGER_NAMESPACE, name = "AddOrUpdateContactResponse")
@XmlType(name = "")
@XmlAccessorType(XmlAccessType.FIELD)
public class AddOrUpdateContactResponse {
 
	/**
	 * Contact modifié ou ajouté.
	 */
	@XmlElement(required = true)
	private ContactWsDto contact;
 
	/**Get contact.
	 * @return the contact
	 */
	public ContactWsDto getContact() {
		return contact;
	}
 
	/**Set contact.
	 * @param contact the contact to set
	 */
	public void setContact(ContactWsDto contact) {
		this.contact = contact;
	}
}

Les annotations xml.bind.annotation

Afin de permettre la sérialisation d’un message en XML, nous devons lui ajouter toute une série d’annotations. Ce sont ces annotations qui vont donner corps à notre flux XML et permettre l’échange de données structurées. Voici une liste des annotations que nous avons utilisés dans nos classes de messages :

@XmlRootElement :

Cette annotation permet de définir un élément de notre fichier XSD, c’est à dire un nœud xml qui caractérise soit une requête soit une réponse mise en jeu lors des échanges avec le web-service. Cette annotation prend deux paramètres:

        • le namespace qui doit être commun à toutes les classes pour obtenir un fichier XSD unique.
        • le nom de la classe.

@XmlType :

Cette annotation permet de transformer nos classes en objets complexes. Elle est utilisée sans namespace dans le cadre des éléments définissant les requêtes et les réponses mais elle est utilisée en incluant le namespace lorsque nous voulons embarquer des types complexes tels que les DTO, comme nous le verrons plus loin.

@XmlAccessorType(XmlAccessType.FIELD) :

Cette annotation permet d’indiquer les champs ou propriétés qui sont sérialisables (XmlAccessType.FIELD : sur tous les champs non statiques).

@XmlElement :

Cette annotation permet d’ajouter des contraintes sur les attributs des classes définissant les échanges, la liste est longue, veuillez-vous référer à la javadoc du package xml.bind.annotations pour plus d’informations.

L’utilisation de certaines annotations pouvant engendrer une incohérence du fichier XSD généré avec l’approche adoptée par l’API Spring Web Services lors de la génération automatique du wsdl, il est important de faire contrôler notre fichier XSD.

Configuration du plugin

Une fois l’ensemble des classes nécessaires à notre web-service implémentées, nous allons configurer le plugin JAXB qui va générer le fichier XSD. La configuration du plugin se fait dans le fichier pom.xml du projet web service serveur.

contact-manager-ws-server/pom.xml :

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>jaxb2-maven-plugin</artifactId>
    <executions>
	<execution>
	    <phase>compile</phase>
            <goals><goal>schemagen</goal></goals>
	<execution>
    </executions>
    <configuration>
        <transformSchemas>
            <transformSchema>
		<uri>http://scub/foundation/web/service/contactService</uri>
		<toFile>contactService.xsd</toFile>
	    </transformSchema>
	</transformSchemas>
	<includes>
	    <include>org/scub/foundation/contact/manager/ws/message/*.java</include>
            <include>org/scub/foundation/contact/manager/ws/dto/*.java</include>
        </includes>
    </configuration>
</plugin>

Choix du namespace de notre fichier xsd, celui-ci doit être identique avec le namespace porté par nos classe java décrivant les échanges.

http://scub/foundation/web/service/contactService

Choix du nom du fichier XSD généré

contactService.xsd

Choix des packages que le plugin va scanner pour rechercher des classes java annotées avec @XmlRootElement et @XmlType.

Définition du chemin du fichier généré.

${project.build.outputDirectory}/schemas
org/scub/foundation/contact/manager/ws/message/*.java
org/scub/foundation/contact/manager/ws/dto/*.java

Nous incluons les messages définissant les échanges et les dto qu’ils contiennent.

Gestion des DTO

Comme nous l’avons vue précédemment, un message peut tout à fait contenir des DTO. Toutefois, pour que ceux-ci soient inclus dans le fichier XSD généré, il va falloir les annoter également. Comme pour les messages, les DTO seront inclus dans le projet web service serveur et il seront annoté de la même façon avec les mêmes annotations.

Voici l’exemple de l’annotation du DTO utilisé par nos classes de messages ci-dessus :

package org.scub.foundation.contact.manager.ws.dto;
 
import java.io.Serializable;
import java.util.Calendar;
import java.util.List;
 
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;
 
import org.scub.foundation.contact.manager.ws.namespace.Namespace;
 
/**
 * DTO identique à ContactDto.
 * Utilisé pour le transport des informations dans les échanges du web-service
 * @author Arnaud Brochain (arnaud.brochain@scub.net)
 */
@XmlType(namespace = Namespace.CONTACT_MANAGER_NAMESPACE, name = "ContactWsDto")
@XmlAccessorType(XmlAccessType.FIELD)
public class ContactWsDto implements Serializable {
 
    private static final long serialVersionUID = 7728546857440718715L;
 
    private Long id;
 
    @XmlElement(nillable = false, required = true)
    private String nom;
 
    @XmlElement(nillable = false, required = true)
    private String prenom;
 
    private Calendar dateNaissance;
 
    @XmlElement(nillable = false, required = true)
    private IdLabelWsDto civilite;
 
    @XmlElement(nillable = false, required = true)
    private List telephones;
 
    @XmlElement(nillable = false, required = true)
    private List emails;
 
    /**
     * Get the value of id.
     * @return the id
     */
    public Long getId() {
        return id;
    }
 
    /**
     * Set the value of id.
     * @param id the id to set
     */
    public void setId(Long id) {
        this.id = id;
    }
 
    /**
     * Get the value of nom.
     * @return the nom
     */
    public String getNom() {
        return nom;
    }
 
    /**
     * Set the value of nom.
     * @param nom the nom to set
     */
    public void setNom(String nom) {
        this.nom = nom;
    }
 
    /**
     * Get the value of prenom.
     * @return the prenom
     */
    public String getPrenom() {
        return prenom;
    }
 
    /**
     * Set the value of prenom.
     * @param prenom the prenom to set
     */
    public void setPrenom(String prenom) {
        this.prenom = prenom;
    }
 
    /**
     * Get the value of telephones.
     * @return the telephones
     */
    public List getTelephones() {
        return telephones;
    }
 
    /**
     * Set the value of telephones.
     * @param telephones the telephones to set
     */
    public void setTelephones(List telephones) {
        this.telephones = telephones;
    }
 
    /**
     * Get the value of civilite.
     * @return the civilite
     */
    public IdLabelWsDto getCivilite() {
        return civilite;
    }
 
    /**
     * Set the value of civilite.
     * @param civilite the civilite to set
     */
    public void setCivilite(IdLabelWsDto civilite) {
        this.civilite = civilite;
    }
 
    /**
     * Return the value of dateNaissance.
     * @return the dateNaissance
     */
    public Calendar getDateNaissance() {
        return dateNaissance;
    }
 
    /**
     * Modify the value of dateNaissance.
     * @param dateNaissance the dateNaissance to set
     */
    public void setDateNaissance(Calendar dateNaissance) {
        this.dateNaissance = dateNaissance;
    }
 
	/**Get emails.
	 * @return the emails
	 */
	public List getEmails() {
		return emails;
	}
 
	/**Set emails.
	 * @param emails the emails to set
	 */
	public void setEmails(List emails) {
		this.emails = emails;
	}
}

En résumé, si l’on désire utiliser des DTO dans un web-service, il va falloir le déclarer et l’annoter dans le projet web service serveur. Si il existe une correspondance entre ce nouveau DTO et l’un des DTO déjà présent dans un projet core-interface, alors on pourra spécifier une configuration de mapping à dozer pour passer de l’un à l’autre :

<mapping>
    <class-a>org.scub.foundation.framework.base.dto.IdLabelDto</class-a>
    <class-b>org.scub.foundation.contact.manager.ws.dto.IdLabelWsDto</class-b>
</mapping>

Une fois la configuration effectuée, la génération du fichier xsd s’effectue en utilisant le goal Maven “Generate XSD from POJO”.

Configuration du marshaller

Nous disposons maintenant de notre fichier XSD qui respecte les standards requis par l’api Spring Web Service. Il faut maintenant configurer le marshaller pour automatiser les transformations entre message Xml et objet java. Cela s’effectue dans le fichier de config conf/common/resources/services-servlet.xml :

<!--Déclaration Marshaller Jaxb2 -->
<!--Associe les classes contenant l'annotation @xmlRootElement dans "basePackage"-->
<!--au fichier xsd définit par "schema".	-->
<bean id="marshaller" class="org.scub.foundation.framework.ws.marshaller.ModelScanningMarshaller">
    <property name="schema" value="classpath:/schemas/contactService.xsd" />
    <property name="basePackage" value="org.scub.foundation.contact.manager.ws" />
 </bean>
 
<!-- Mise en intéraction du marshaller et des endpoints	-->
<bean id="marshallingPayloadMethodProcessor" class="org.springframework.ws.server.endpoint.adapter.method.MarshallingPayloadMethodProcessor">
    <constructor-arg ref="marshaller" />
    <constructor-arg ref="marshaller" />
</bean>

Chemin du fichier XSD définissant les messages xml

/schemas/contactService.xsd

Packages contenant les classes java annotées avec l’élément @XmlRootElememt :

org.scub.foundation.contact.manager.ws

Implémentation de l’EndPoint

Maintenant que nos classes sont définies, que notre fichier xsd est généré et que le marshaller est configuré, nous allons développer la classe Endpoint qui recevra les requêtes et enverra les réponses correspondantes.

Exemple dans contact-manager-ws-server (src/main/java/ContactServiceEndPoint.java) :

	/**
	 * Handler du web service addOrUpdateContact.
	 * @param request AddOrUpdateContactRequest
	 * @return AddOrUpdateContactResponse
	 */
	@PayloadRoot(namespace = Namespace.CONTACT_MANAGER_NAMESPACE, localPart = LOCAL_PART_ADD_OR_UPDATE_CONTACT)
	@ResponsePayload
	public AddOrUpdateContactResponse addOrUpdateContactHandler(@RequestPayload AddOrUpdateContactRequest request) {
		final AddOrUpdateContactResponse response = new AddOrUpdateContactResponse();
		final ContactDto contactDto = mapperDozerBean.map(request.getContact(), ContactDto.class);
		final ContactWsDto contactWsDto = mapperDozerBean.map(contactService.ajouterOuModifierContact(contactDto), ContactWsDto.class);
		response.setContact(contactWsDto);
		return response;
	}

Lors de l’envoi d’une request de type AddOrUpdateContactRequest, l’appel sera routé vers cette méthode grâce à l’annotation @PayLoadRoot ( à noter, la valeur du localPart : LOCAL_PART_ADD_OR_UPDATE_CONTACT = « AddOrUpdateContactRequest »).

L’import rmi du service contactService de contact-manager-core se fait comme dans tous les noyaux (configuration dans le fichier rmiServiceImporterSpecContext.xml).

Ne pas oublier l’annotation @Endpoint portée par la classe ContactServiceEndPoint. Sans cette annotation aucunes requêtes ne seraient routées vers les handlers correspondants.

Génération de la wsdl

Un fichier wsdl est une description en xml d’un web-service proposé par une application. C’est en récupérant ce fichier qu’une application client sait quel web-service est accessible, comment l’utiliser et comment interpréter ses réponses. Grâce à Spring-ws, le fichier wsdl sera automatiquement généré et exposé lors du déploiement de notre projet dans le serveur d’application. Après l’utilisation de la tâche Maven “Déployer dans Jetty” sur le projet contact-manager-ws-server, le fichier wsdl est accessible à l’adresse suivante ; http://localhost:8080/contact-manager-ws-server-1.0-SNAPSHOT/services/contactServiceWsdl.wsdl

Toutefois cette exposition du fichier wsdl ne s’effectue pas automatiquement par défaut. Pour que cela se fasse, il faut le définit dans le fichier sevlet-context.xml :

<!-- Génération et publication de la wsdl à partir du fichier contactService.xsd -->
<sws:dynamic-wsdl id="contactServiceWsdl" portTypeName="contactServiceWsdl" locationUri="/services/" targetNamespace="http://scub/foundation/web/service/contactService">
    <sws:xsd location="classpath:/schemas/contactService.xsd" />
</sws:dynamic-wsdl>

Consommation de notre web service

Implémenter le consumer

Comme pour la partie serveur de notre web-service, nous allons devoir mettre en place un marshaller qui va automatiquement transformer les messages XML en objet java. Il est associé à un bean WebServiceTemplate qui va assurer les appels au web service.

Dans contact-manager-ws-client/conf/common/ressources/applicationContext.xml :

<!-- Définition du marshaller	-->
<bean id="marshaller" class="org.scub.foundation.framework.ws.marshaller.ModelScanningMarshaller">
    <property name="schema" value="classpath:xsd/contactServiceWsdl.xsd" />
    <property name="basePackage" value="org.scub.foundation.contact.manager.ws.client.side.message" />
</bean>
 
<!-- Classe permettant l'envoie et la récéption de message XML	-->
<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate" autowire="byName">     
    <property name="marshaller" ref="marshaller" />
    <property name="unmarshaller" ref="marshaller" />
    <property name="defaultUri" value="http://localhost:8080/contact-manager-ws-server-1.0-SNAPSHOT/services/"/>
</bean>

On configure l’url à laquelle le webServiceTemplate va envoyer les requêtes via la propriété defaultUri Cette propriété doit être en cohérence avec le paramètre incomingWsdlPath du plugin maven-scub-foundation-ws-client-plugin.

Une fois la configuration terminée, la consommation du web-service est très simple à effectuer.  Il suffit pour cela d’implémenter notre interface de service dans un projet web service client. Dans le projet exemple contact-manager-ws-client-interface, celà est fait via la classe ContactServiceConsumer.

public class ContactServiceConsumerImpl implements ContactServiceConsumer {
 
	private MapperDozerBean mapperDozerBean;
 
	private WebServiceTemplate webServiceTemplate;
 
	/**
	 * {@inheritDoc}
	 */
	public ContactDto getContactById(Long idContact) {
		final GetContactByIdRequest request = new GetContactByIdRequest();
		request.setId(idContact);
		final GetContactByIdResponse response = (GetContactByIdResponse) webServiceTemplate.marshalSendAndReceive(request);
		return mapperDozerBean.map(response.getContact(), ContactDto.class);
	}

On se retrouve donc avec un bean qui va communiquer avec notre projet web service serveur en utilisant notre web-service. Il ne reste plus qu’à inclure ce bean dans les projets voulus pour pouvoir utiliser notre web-service.

Télécharger les sources

Les sources du projet Eclipse pour ce tutoriel sont téléchargeables sur Source Forge à l’adresse suivante.