mercredi 22 décembre 2010

Créer un service web XML avec JAX-WS et Maven


JAX-WS 2.0 ou la JSR 224 constitue une pile normée qui réduit considérablement la complexité de mise en oeuvre d'un service web.
Il est cependant indispensable de posséder quelques notions de base sur les technologies liées aux services web.

Notions fondamentales préalables


Tout d'abord, il faut dire un mot sur XML, ce "langage extensible de balisage". XML est un moyen indépendant de toute plateforme pour représenter des informations structurées.
Dans le cadre des services web, XML sert de base à la communication entre les services et leurs clients.
SOAP est une grammaire XML dédié à la transmission de messages entre objets distants. Un message SOAP se compose d'une enveloppe (les informations nécessaire à l'acheminement et à son traitement) et d'un modèle de données (le format du message et son contenu).
WSDL est une grammaire XML qui décrit les services distribués sur le réseau comme un ensemble de points qui opèrent à partir de messages.
Je vous invite à consulter mon petit lexique des services webs.

Vérifions ...


La bonne nouvelle c'est que l'api JAX-WS fait partie de l'API standard  de votre JDK à partir de la version 6.
Quant aux implémentations plusieurs sont disponibles : Metro (SUN/Oracle), CXF (Apache) , Axis 2 (Apache).
Metro est intégré d'office dans le JDK 6. C'est l'implémentation de référence de cette API.
Comme toutes les implémentations de référence elle couvre l'intégralité de la JSR 224 et bien plus.
Metro est aussi intéressant pour la collaboration des ingénieurs de SUN et de Microsoft : Metro affiche une compatibilité avec .NET 3.0 et .NET.3.5.
Vous trouverez dans le dossier JAVA_HOME/bin deux utilitaires fournis avec l'implémentation de référence:
  • wsgen : génère les ressources nécessaire au déploiement d'un webservice JAX-WS.
  • wsimport : importe un WSDL et génère les classes nécessaires à la réalisation d'un client.

Un petit test en ligne de commande permet de connaître la version de l'implémentation de référence :
macbook-de-olivier-schmitt:Commands oschmitt$ wsgen -version
JAX-WS RI 2.1.6 in JDK 6
Est-ce ok pour vous ?

Création du projet Yellow Book Service


Nous allons utiliser Maven pour réaliser ce service web.
Je vous conseille d'utilisez un IDE qui supporte Maven correctement comme Netbeans ou IntelliJ.
Un conteneur JEE qui supporte JAX-WS vous permettra également de vous concentrer sur l'essentiel.
Utilisez par exemple Glassfish 3.0.1 dans sa version "web profile" pour déployer le WAR qui contient le service web. Il est tout à fait possible d'utiliser Tomcat mais cela demande une configuration particulière (décrite par ailleurs dans les instructions d'installation de Metro).
Nous utiliserons le POM Corporate fourni depuis ce billet.
Tout d'abord il convient de créer un projet Maven avec un packaging de type war. En effet, un service web est souvent déployé depuis une application web (WAR).
Le plugin archetype permet de créer rapidement un projet Maven.
Exemple testé avec Maven 2.011, 2.1.0, 2.2.1, 3.0 :
mvn archetype:generate -DarchetypeArtifactId=maven-archetype-webapp -DgroupId=jee.architect.cookbook.jws -DartifactId=yellow-book-service -Dversion=1.0-SNAPSHOT -Dpackage=jee.architect.cookbook.jws.yellowbook


Ajoutez la référence au POM corporate :
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
   <modelVersion>4.0.0</modelVersion>
        
   <parent>
       <groupId>jee.architect.cookbook</groupId>
       <artifactId>corporate-pom</artifactId>
       <version>1.0</version>
   </parent>
        
   <groupId>jee.architect.cookbook.jws</groupId>
   <artifactId>yellow-book-service</artifactId>
   <version>1.0-SNAPSHOT</version>
   <packaging>war</packaging>
   <name>Yellow Book Service</name>

Notre premier service web


JAX-WS propose deux approches classiques : "top down" et "bottom up".
L'approche top down consiste à partir d'un WSDL pour générer des éléments Java, tandis que l'approche "bottom up" consiste à partir du code Java.
Nous utiliserons ici l'approche "bottom up".
Avec JAX-WS cette approche se traduit par l'utilisation d'annotations dédiées que l'on pose sur des POJOs.
Bien souvent, un service web expose une fonction métier modélisée sous la forme d'une interface.
On parle aussi de services métiers déployés au sein d'une couche métier qui définit (interfaces) et implémente (classes concrètes, mapping ORM, ...) l'ensemble de la logique métier d'une application, d'un système d'information ou de l'entreprise.
Ainsi, le service web n'est que la partie émergée du métier.
Parfois plusieurs modes d'exposition d'une fonction métier peuvent cohabiter pour des raisons techniques ou pratiques : EJB (transactionnalité, ... ), REST (consultation simple, ...), API à embarquer, ....

Nous considèrerons ainsi qu'il existe une interface qui définit notre service métier :
public interface YellowBook {
   String getPhoneNumber(String firstName, String lastName);
}

Notre service des pages jaunes fournit un numéro de téléphone pour un nom et un prénom.
Cette interface sera éventuellement implémentée par plusieurs classes.
Ici, notre classe Java qui va implémenter le service web va utiliser ce contrat.

public class YellowBookWSImpl implements YellowBook  {

   public String getPhoneNumber(String firstName, String lastName){          
       return "999999999";
   }
 
}

A ce stade notre classe ne se distingue en rien d'une classe Java standard.
Nous allons utiliser les annotations de l'API JAX-WS pour la transformer en service web.
Tout d'abord l'annotation @WebService qui transforme une classe en service web.
@WebService
public class YellowBookWSImpl implements YellowBook  {

   public String getPhoneNumber(String firstName, String lastName){          
       return "999999999";
   }
 }

Cette classe est désormais un service web qui présente une opération "getPhoneNumber". Par défaut, ce sont toutes les méthodes de votre classe qui deviennent des opérations.
L'annotation @WebService propose plusieurs attributs importants qui déterminent la manière dont votre service web sera exposé.
La JSR 224 définit une correspondance entre Java et WSDL. In fine, vos clients ne connaitront probablement que le WSDL.
Il est donc important de maîtriser cette correspondance :
  • serviceName : le nom du service web.
  • name : le nom du type de port du service web. Par défaut c'est le nom de la classe ou de l'interface annotée, ici, "YellowBookWSImpl".
  • targetNamespace : espace de nommage cible. Par défaut c'est le nom complet du package inversé avec "http://" comme préfixe.
  • portName : le nom du port ou point de terminaison.
Nous pouvons affiner notre définition :
@WebService(name="YellowBookPortType",serviceName="YellowBookService", portName = "YellowBookPort")
public class YellowBookWSImpl implements YellowBook  {

   public String getPhoneNumber(String firstName, String lastName){          
       return "999999999";
   }
}

JAX-WS propose aussi des annotations à poser sur les méthodes du service web.
Elles permettent de piloter la définition du service (le WSDL) notamment au niveau des données échangées en entrée et en sortie.
Dans notre exemple, nous avons pas besoin d'utiliser ces annotations car le type de données String est pris en charge nativement par JAXB.
JAX-WS sous traite la sérialisation XML des objets Java à JAXB.
JAXB proposera une représentation XML de vos données ainsi qu'un schéma XML associé qui sera associé au WSDL.
Nous ne traiterons pas de cette problématique dans cet article mais probablement dans un autre !

Utilisation du plugin JAX-WS


Ce plugin permet de générer le WSDL du service web.
Pour que le WSDL soit toujours synchronisé avec la classe d'implémentation du service web, il suffit de lier l'exécution du goal "wsgen" à la phase "process-classes".
Cette phase vient après la compilation, or le plugin a besoin de la classe compilée pour générer le WSDL.
En attachant le déclenchement du goal "wsgen" à cette phase on est certain de disposer de la classe compilée.
Consultez la documentation Maven pour le détail du cycle de vie d'un projet.
   <build>
       <plugins>
           <plugin>
               <groupId>org.codehaus.mojo</groupId>
               <artifactId>jaxws-maven-plugin</artifactId>
               <version>1.10</version>
               <executions>
                   <execution>
                       <phase>process-classes</phase>
                       <goals>
                           <goal>wsgen</goal>
                       </goals>
                   </execution>
               </executions>
               <configuration>
                   <sei>jee.architect.cookbook.jws.yellowbook.YellowBookWSImpl</sei>
                   <genWsdl>true</genWsdl>
                   <keep>true</keep>
                   <resourceDestDir>${basedir}/src/main/webapp/WEB-INF/wsdl</resourceDestDir>
               </configuration>
           </plugin>
       </plugins>
   </build>
Exécutez un clean install pour déclencher la génération du WSDL et du schéma ou des schémas associés pour les types de données.
Pour que JAX-WS utilise le WSDL généré il faut indiquer l'emplacement de ce fichier grâce à l'attribut "wsdlLocation":
@WebService(name="YellowBookPortType",serviceName="YellowBookService", portName = "YellowBookPort",wsdlLocation="YellowBookService.wsdl")
public class YellowBookWSImpl implements YellowBook  {

   public String getPhoneNumber(String firstName, String lastName){          
       return "999999999";
   }
}

Déployons


Nous devons d'abord construire le WAR via une suite de goal Maven
mvn clean install
Ensuite déployez ce WAR sur un serveur JEE compatible JAX-WS comme Glassfish 3.0.1 Web Profile.
Glassfish est fourni avec une CLI puissante, asadmin (GLASSFISH_HOME/bin/asadmin).
Démarrez Glassfish :
./asadmin start-domain
Puis déployez le WAR :
./asadmin deploy /Users/oschmitt/java/github/the-jee-architect-cookbook/jws/yellow-book-service/target/yellow-book-service-1.0-SNAPSHOT.war
Vérifiez ensuite le déploiement de votre service web : http://localhost:8080/YellowBook/YellowBookService
Les sources (produites avec Netbeans 6.9.1 et Maven 3.0.1) de cet article sont disponibles sur le dépôt Github.

Contrat Creative Commons
the jee architect cookbook by Olivier SCHMITT est mis à disposition selon les termes de la licence Creative Commons Paternité - Pas d'Utilisation Commerciale - Pas de Modification 3.0 Unported.

Aucun commentaire:

Enregistrer un commentaire