Développer un Web Service avec JAX-WS et le tester avec SOAPUI, en 5 minutes

Thierry Leriche-Dessirier

Développer un Web service est devenu bien plus simple qu'on ne l'imagine. Ce petit article en fait la preuve, à travers des étapes simples, et en seulement quelques minutes. Commentez

- Titre : Développer un Web Service avec JAX-WS et le tester avec SOAPUI, en 5 minutes

- Auteur : Thierry Leriche-Dessirier

- Parution : 15 mai 2012

- Public visé :

- Licence : Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ® 2011 Thierry Leriche-Dessirier. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Introduction

- I-A. À propos

- I-B. Avant de commencer

- II. Découverte du projet d'exemple

- II-A. Télécharger, installer et importer le projet d'exemple

- II-B. Ce que fait déjà le projet d'exemple

- III. Action

- III-A. Maven

- III-B. Création du Web service

- III-C. Tester le Web service

- III-D. Des retours plus complexes

- IV. Conclusions

- V. Remerciements

- VI. Annexes

- VI-A. Quelques définitions

- VI-B. Liens

- VI-C. Les fichiers importants en entier

I - Introduction

Ce court article traite de l'écriture de Web Services (SOAP) en Java. Nous verrons qu'il est très facile de créer ses premiers Web Services à l'aide de JAX-WS, en suivant quelques étapes simples.

On parle aussi de Web Services étendus qui s'appuient sur des standards, des piles spécifiques pour la sécurité et l'interopérabilité, et qui sont particulièrement adaptés à la manipulation de services.

Dans le passé, les développeurs utilisaient des bibliothèques, comme Axis ou Xfire, avec plus ou moins de peines (processus complexes, générations longues, synchronisations et déploiements pénibles, performances douteuses, etc.). Heureusement, les nouvelles API, avec JAX-WS en tête, changent la donne.

Dans ce tutoriel, nous allons utiliser l'implémentation de référence « JAX-WS RT » (aussi connue sous le nom « Metro ») de JAX-WS, pour exposer via des Web Services les fonctionnalités de notre application Web fictive. Nous utiliserons le logiciel SoapUI pour vérifier que tout fonctionne.

Dans un prochain article, je m'intéresserai aux Web Services REST, qui entrainent l'utilisation d'autres concepts et mécanismes. Je n'en parlerai donc pas ici.

I-A - À propos

Découvrir une technologie n'est pas chose facile. En aborder plusieurs d'un coup l'est encore moins. Partant de ce constat, cet article a été écrit pour aller à l'essentiel. Les points importants sont présentés dans le corps de l'article et les éléments secondaires sont expliqués en annexes.

I-B - Avant de commencer

Pour écrire ce tutoriel, j'ai utilisé les éléments suivants :

- Java JDK 1.6.0_24-b07 ;

- Eclipse Indigo 3.7 JEE 64b ;

- Maven 3.0.3 ;

- Tomcat 6.0.29 64b ;

- Pretty Faces 3.3.2 ;

- JAX-WS RT 2.2.5.

II - Découverte du projet d'exemple

II-A - Télécharger, installer et importer le projet d'exemple

Pour commencer, je vous propose de télécharger le fichier Zip « fibowebapp2.zip », contenant un projet Java-Maven d'exemple (une miniwebapp) qui va nous servir de support pour les fonctionnalités présentées dans la suite de cet article.

Compilez le projet d'exemple et importez-le dans Eclipse (comme expliqué dans le tutoriel « Importer un projet Maven dans Eclipse en 5 minutes ») ou dans l'IDE de votre choix.

Installez ensuite la webapp dans le serveur d'application de votre choix, par exemple Tomcat 6, ce que vous pouvez faire directement depuis Eclipse.

Pour suivre ce tutoriel, vous pouvez vous contenter de lire les codes proposés ci-dessous (codes complets en annexes) et de faire confiance aux captures d'écran.

II-B - Ce que fait déjà le projet d'exemple

Le projet d'exemple est une petite webapp permettant de calculer plusieurs fonctions mathématiques célèbres. Cette application Web n'a rien de très complexe. Elle utilise le framework Web JSF, inclus dans JEE depuis la version 5. Les fonctionnalités (calcul de la suite de Fibonacci et du factoriel) servent uniquement d'illustration.

Suite de Fibonacci pour le rang 14

Comme on peut le constater sur la capture d'écran, la webapp calcule la valeur du membre de la suite de Fibonacci pour un rang donné. La Webapp calcule aussi les membres de rangs inférieurs, ce qui permet d'afficher une liste intéressante. En outre, la webapp utilise deux méthodes de calcul. La première met en œuvre un algorithme récursif lent, mais qui donne une valeur exacte. La seconde se sert d'une fonction mathématique rapide dont la justesse des résultats dépend de la précision des constantes internes utilisées. La dernière colonne du tableau de résultat fait apparaitre les erreurs d'approximation.

Approximations dès le rang 62

Cette petite Webapp a été présentée en détail dans l'article « De jolies URL dans vos applications Web JSF avec Pretty Faces ».

Pour réaliser le calcul, la Webapp utilise le service « FiboService » :

FiboService.java

public class FiboService {

// singleton
private static FiboService instance;
public static synchronized FiboService getInstance() {
if (instance == null) {
instance = new FiboService();
}
return instance;
}

// Calcul recursif mais exact
public Long calculerFibonacci(Integer n) {
...
}

// Calcul direct, mais approximatif
public Long calculerApproximationfibonacci(Integer n) {
...
}

...

Quant au bean « FiboBean » qui « manage » la page, il lance les appels qu'il faut pour remplir le bean de résultat « FiboResult » :

FiboResult.java

public class FiboResult {

private Integer rang;
private Long valeurExacte;
private Long valeurApproximative;
private Long approximation;

public FiboResult(Integer rang, Long valeurExacte, Long valeurApproximative) {
this.rang = rang;
this.valeurExacte = valeurExacte;
this.valeurApproximative = valeurApproximative;
this.approximation = Math.abs(valeurExacte - valeurApproximative);
}

...

FiboBean.java

public class FiboBean {

private FiboService fiboService = FiboService.getInstance();
private List<FiboResult> valeurs;
...

public void calculer() {

valeurs = new ArrayList<FiboResult>(rang);
for (int i = 1; i <= rang; i++) {
final FiboResult fiboResult = calculerFiboResult(i);
valeurs.add(fiboResult);
}

Long valeur = fiboService.calculerFibonacci(rang);
}

private FiboResult calculerFiboResult(Integer rang) {
Long valeurExacte = fiboService.calculerFibonacci(rang);
Long valeurApproximative = fiboService.calculerApproximationfibonacci(rang);
FiboResult fiboResult = new FiboResult(rang, valeurExacte, valeurApproximative);
return fiboResult;
}

...

III - Action

III-A - Maven

Durée estimée : 1 minute.

Pour utiliser JAX-WS (JAX-WS RT), il faut ajouter une dépendance dans le fichier « pom.xml ».

Dépendance dans le pom.xml

<!-- JAX-WS RT -->
<dependency>
<groupId>com.sun.xml.ws</groupId>
<artifactId>jaxws-rt</artifactId>
<version>2.2.5</version>
</dependency>

Puis relancer une installation Maven.

Commande Maven

mvn clean install eclipse:eclipse

En fonction des éléments déjà présents sur le disque dur, le résultat de l'installation Maven devrait ressembler à la trace suivante :

Commande Maven

C:\...\fibowebapp>mvn clean install eclipse:eclipse

[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building fibowebapp 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 11.025s
[INFO] Finished at: Thu Apr 30 20:59:22 CEST 2012
[INFO] Final Memory: 10M/53M
[INFO] ------------------------------------------------------------------------

On doit ensuite faire un refresh (touche F5) dans Eclipse pour faire apparaitre JAX-WS (et ses dépendances) dans la liste des bibliothèques référencées.

III-B - Création du Web service

Durée estimée : 1 minute.

Pour fabriquer un Web service avec JAX-WS, c'est relativement simple. Il suffit de créer un bean qu'on va annoter avec « @WebService ». Les méthodes « public » de ce bean seront nos services.

FibonacciWebService.java

package com.dvp.fibowebapp.ws;

import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;

@WebService
@SOAPBinding(style = Style.RPC)
public class FibonacciWebService {

public Long fibonacci(Integer rang) {
return 0L;
}

}

Pour le moment, le bean est relativement simple. Il renvoie toujours zéro. Pour réaliser le calcul, on va s'inspirer de « FiboBean », présenté plus haut.

FibonacciWebService.java

@WebService
@SOAPBinding(style = Style.RPC)
public class FibonacciWebService {

private final FiboService fiboService = FiboService.getInstance();

public Long fibonacci(Integer rang) {
Long result = fiboService.calculerFibonacci(rang);
return result;
}

Il faut maintenant « mapper » ce service. Pour cela, il faut créer le fichier « sun-jaxws.xml » dans le dossier « WEB-INF » de la webapp.

sun-jaxws.xml

<?xml version="1.0" encoding="UTF-8"?>
<endpoints xmlns="http://java.sun.com/xml/ns/jax-ws/ri/runtime" version="2.0">

<endpoint
name="fibonacci"
implementation="com.dvp.fibowebapp.ws.FibonacciWebService"
url-pattern="/fibonacci" />
</endpoints>

Et bien entendu, il faut ajouter un filtre dans le « web.xml ». Pour utiliser JAX-WS, on peut utiliser simplement la servlet « WSServlet ».

web.xml

...

<listener>
<listener-class>com.sun.xml.ws.transport.http.servlet.WSServletContextListener</listener-class>
</listener>
<servlet>
<servlet-name>WSServlet</servlet-name>
<servlet-class>com.sun.xml.ws.transport.http.servlet.WSServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>WSServlet</servlet-name>
<url-pattern>/fibonacci</url-pattern>
</servlet-mapping>

...

À ce stade, le Web service est prêt. Le serveur va générer le WSDL (le fichier qui décrit le service) à l'exécution. On peut le voir directement dans Firefox en demandant l'adresse « http://…/fibowebapp/fibonacci?wsdl ».

WSDL

WSDL généré (http://.../fibowebapp/fibonacci?wsdl)

<?xml version='1.0' encoding='UTF-8'?>
<definitions
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
xmlns:wsp="http://www.w3.org/ns/ws-policy" xmlns:wsp1_2="http://schemas.xmlsoap.org/ws/2004/09/policy"
xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://ws.fibowebapp.dvp.com/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://schemas.xmlsoap.org/wsdl/" targetNamespace="http://ws.fibowebapp.dvp.com/"
name="FibonacciWebServiceService">
<types />
<message name="fibonacci">
<part name="arg0" type="xsd:int" />
</message>
<message name="fibonacciResponse">
<part name="return" type="xsd:long" />
</message>
<portType name="FibonacciWebService">
<operation name="fibonacci">
<input
wsam:Action="http://ws.fibowebapp.dvp.com/FibonacciWebService/fibonacciRequest"
message="tns:fibonacci" />
<output
wsam:Action="http://ws.fibowebapp.dvp.com/FibonacciWebService/fibonacciResponse"
message="tns:fibonacciResponse" />
</operation>
</portType>
<binding name="FibonacciWebServicePortBinding" type="tns:FibonacciWebService">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http"
style="rpc" />
<operation name="fibonacci">
<soap:operation soapAction="" />
<input>
<soap:body use="literal" namespace="http://ws.fibowebapp.dvp.com/" />
</input>
<output>
<soap:body use="literal" namespace="http://ws.fibowebapp.dvp.com/" />
</output>
</operation>
</binding>
<service name="FibonacciWebServiceService">
<port name="FibonacciWebServicePort" binding="tns:FibonacciWebServicePortBinding">
<soap:address location="http://localhost:8080/fibowebapp/fibonacci" />
</port>
</service>
</definitions>

III-C - Tester le Web service

Durée estimée : 1 minute.

On va maintenant tester le Web service à l'aide du logiciel gratuit Soap UI.

Soap UI

Pour commencer, il faut créer un nouveau projet à l'aide du menu « File/New SoapUi project ». L'idéal est que le serveur soit démarré durant cette étape, pour que SoapUI puisse s'y connecter.

Nouveau projet

Projet Fibonacci

Le logiciel va chercher toutes les informations dans le WSDL et créer un premier jeu de test.

Test

Requête

<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ws="http://ws.fibowebapp.dvp.com/">
<soapenv:Header/>
<soapenv:Body>
<ws:fibonacci>
<arg0>?</arg0>
</ws:fibonacci>
</soapenv:Body>
</soapenv:Envelope>

Pour vérifier que tout fonctionne, il suffit de remplacer les valeurs manquantes dans le XML (à gauche) et signalées par des points d'interrogation (?) puis de cliquer sur la flèche.

Résultat pour le rang 14

Réponse

<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<ns2:fibonacciResponse xmlns:ns2="http://ws.fibowebapp.dvp.com/">
<return>377</return>
</ns2:fibonacciResponse>
</S:Body>
</S:Envelope>

Il y a tout de même un petit détail qui choque, c'est que le XML n'est pas très clair. En particulier, quand on indique le rang, il faut remplir la balise « arg0 ». Ici, ce n'est pas très compliqué, car il n'y a qu'un seul paramètre, mais il faut imaginer le cas où on en a plusieurs. Pour améliorer le Web service, on va simplement compléter la méthode de calcul avec l'annotation « @WebParam ».

FibonacciWebService.java

@WebService
@SOAPBinding(style = Style.RPC)
public class FibonacciWebService {

...

public Long fibonacci(@WebParam(name = "rang") Integer rang) {
...

On relance le serveur et on fait un « refresh » dans SoapUI pour avoir la nouvelle version du WSDL, avec des paramètres nommés.

Paramètre rang

Requête

<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ws="http://ws.fibowebapp.dvp.com/">
<soapenv:Header/>
<soapenv:Body>
<ws:fibonacci>
<rang>?</rang>
</ws:fibonacci>
</soapenv:Body>
</soapenv:Envelope>

III-D - Des retours plus complexes

Durée estimée : 1 minute.

On va maintenant ajouter une méthode de service qui renvoie une liste de résultats en utilisant les deux algorithmes présentés plus haut. La méthode renverra un tableau d'objets dont on spécifiera la taille dans l'appel (histoire d'avoir un second paramètre).

FibonacciWebService.java

@WebService
@SOAPBinding(style = Style.RPC)
public class FibonacciWebService {

...

public FiboDTO[] fibonacciList(
@WebParam(name = "rang") Integer rang,
@WebParam(name = "limit")Integer nb) {

... // code en annexe
}
...

Ici, je retourne des éléments de type « FiboDTO » et non de type « FiboResult ». J'ai pris l'habitude de créer des types spécifiques pour mes objets de retour et de paramètre de mes Web services afin de ne pas exposer mon métier directement. En plus de ne pas dévoiler le contenu de mon domaine, cela me permet d'écrire des objets légers. À titre d'illustration, on peut imaginer un Web service renvoyant le nom et le prénom d'un utilisateur. Je vais alors créer un bean ne contenant que ces deux informations, plutôt que de renvoyer la liste complète des informations (âge, adresse, etc.) dudit utilisateur.

FiboDTO.java

public class FiboDTO {

private Integer rang;
private Long valeurExacte;
private Long valeurApproximative;
private Long approximation;

public FiboDTO() {
super();
}

...

De nouveau, je relance le serveur et je rafraichis SoapUI. Mon nouveau service apparait dans la liste et je peux tester comme précédemment.

Approximation dès le rang 62

Réponse

<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<ns2:fibonacciListResponse xmlns:ns2="http://ws.fibowebapp.dvp.com/">
<return>
<item>
<approximation>1</approximation>
<rang>63</rang>
<valeurApproximative>6557470319843</valeurApproximative>
<valeurExacte>6557470319842</valeurExacte>
</item>
<item>
<approximation>1</approximation>
<rang>62</rang>
<valeurApproximative>4052739537882</valeurApproximative>
<valeurExacte>4052739537881</valeurExacte>
</item>
<item>
<approximation>0</approximation>
<rang>61</rang>
<valeurApproximative>2504730781961</valeurApproximative>
<valeurExacte>2504730781961</valeurExacte>
</item>
...
</return>
</ns2:fibonacciListResponse>
</S:Body>
</S:Envelope>

Et voilà…

IV - Conclusions

Comme on vient de le voir, c'est donc très simple et très rapide d'exposer (i.e. écrire) un Web Service à l'aide de JAX-WS. Nous n'avons abordé que les points-clés, mais cela devrait être suffisant pour bien débuter. Je vous recommande néanmoins la lecture des tutoriels Mickael Baron (cf. liens en annexes) à propos du SOA (Service Oriented Architecture) pour approfondir la question.

Le code final de ce tutoriel est disponible dans le fichier ZIP fibowebapp3.zip.

Vos retours nous aident à améliorer nos publications. N'hésitez donc pas à commenter cet article sur le forum : Commentez

Retrouvez mes autres tutoriels rapides sur developpez.com à l'adresse https://thierry-leriche-dessirier.developpez.com/#page_articles

V - Remerciements

Je tiens à remercier, en tant qu'auteur du tutoriel, toutes les personnes qui m'ont aidé et soutenu. Je pense tout d'abord à mes collègues qui subissent mes questions au quotidien, mais aussi à mes contacts et amis du Web, dans le domaine de l'informatique ou non, qui m'ont fait part de leurs remarques et critiques. Bien entendu, je n'oublie pas l'équipe de developpez.com qui m'a guidé dans la rédaction de cet article et m'a aidé à le corriger et le faire évoluer, principalement sur le forum.

Plus particulièrement j'adresse mes remerciements à Mickael Baron (keulkeul), Claude Leloup, Robin56, Nemek et lunatix.

VI - Annexes

VI-A - Quelques définitions

Pour compléter cet article, voici quelques passages, issus de Wikipedia, à propos des éléments abordés.

Service Web : C'est « un programme informatique permettant la communication et l'échange de données entre applications et systèmes hétérogènes dans des environnements distribués. [..] Le concept a été précisé et mis en œuvre dans le cadre de Web Services Activity2, au W3C, particulièrement avec le protocole SOAP. [..] Le concept s'enrichit avec l'approfondissement des notions de ressource et d'état, dans le cadre du modèle REST, et l'approfondissement de la notion de service, avec le modèle SOA. Dans sa présentation la plus générale, un service Web se concrétise par un agent, réalisé selon une technologie informatique précise, par un fournisseur du service. Un demandeur, à l'aide d'un agent de requête, utilise ce service. Fournisseur et demandeur partagent une même sémantique du service Web, tandis qu'agent et agent de requête partagent une même description du service pour coordonner les messages qu'ils échangent. Il existe plusieurs technologies derrière le terme services Web : 1) les services Web de type REST (Representational state transfer) exposent entièrement ces fonctionnalités comme un ensemble de ressources (URI) identifiables et accessibles par la syntaxe et la sémantique du protocole HTTP. [..] ; 2) les Services Web WS-* exposent ces mêmes fonctionnalités sous la forme de services exécutables à distance. Leurs spécifications reposent sur les standards SOAP et WSDL pour transformer les problématiques d'intégration héritées du monde Middleware en objectif d'interopérabilité. »

SOAP : c'est « un protocole de RPC orienté objet bâti sur XML. Il permet la transmission de messages entre objets distants [..] Le transfert se fait le plus souvent à l'aide du protocole HTTP, mais peut également se faire par un autre protocole, comme SMTP. Le protocole SOAP est composé de deux parties : 1) une enveloppe, contenant des informations sur le message lui-même afin de permettre son acheminement et son traitement ; 2) un modèle de données, définissant le format du message, c'est-à-dire les informations à transmettre. »

VI-B - Liens

Je vous invite à lire plusieurs articles de Mickael Baron (dans la rubrique « Architectures Orientées Services (SOA) »), dont je me suis inspiré, sur des sujets connexes, à l'adresse : https://mbaron.developpez.com/#LV

QR Code vers les articles de Mickael Baron sur le SOA

Le logiciel SoapUI est téléchargeable à l'adresse http://www.soapui.org

QR Code vers SoapUI

Retrouvez mes autres tutoriels sur developpez.com à l'adresse https://thierry-leriche-dessirier.developpez.com/#page_articles

QR Code vers mes articles

Ajoutez-moi à vos contacts à l'aide du QR Code suivant :

QR Code contenant ma vCard

VI-C - Les fichiers importants en entier

FiboService.java

package com.dvp.fibowebapp;

import java.util.HashMap;
import java.util.Map;

public class FiboService {

private final static double NOMBRE_OR = 1.61803398874989;
private final static double RACINE_5 = 2.236067977499;

private static FiboService instance;

private static Map<Integer, Long> mapExact;
private static Map<Integer, Long> mapApproximation;

private FiboService() {
mapExact = new HashMap<Integer, Long>();
mapApproximation = new HashMap<Integer, Long>();
}

public static synchronized FiboService getInstance() {
if (instance == null) {
instance = new FiboService();
}
return instance;
}

public Long calculerFibonacci(Integer n) {

// REGLE RG024.4
if (n <= 0) {
throw new IllegalArgumentException("On ne calcule que pour des nombres positifs");
}

// REGLE RG024.1 : f(1) = 1
// REGLE RG024.2 : f(2) = 1
if (n == 1 || n == 2) {
return 1L;
}

// REGLE RG024.5
// REGLE RG024.6
Long valeur = mapExact.get(n);
if (valeur != null) {
return valeur;
}

// REGLE RG024.3.x : f(n) = f(n-1) + f(n-2)
valeur = calculerFibonacci(n - 1) + calculerFibonacci(n - 2);
mapExact.put(n, valeur);
return valeur;

}

public Long calculerApproximationfibonacci(Integer n) {
if (n <= 0) {
throw new IllegalArgumentException("On ne calcule que pour des nombres positifs");
}

if (n == 1 || n == 2) {
return 1L;
}

Long valeur = mapApproximation.get(n);
if (valeur != null) {
return valeur;
}

final double nominateur = Math.pow(NOMBRE_OR, n);

final double result = nominateur / RACINE_5;
valeur = Math.round(result);
mapApproximation.put(n, valeur);
return valeur;
}

}

FiboResult.java

package com.dvp.fibowebapp;

public class FiboResult {

private Integer rang;
private Long valeurExacte;
private Long valeurApproximative;
private Long approximation;

public FiboResult(Integer rang, Long valeurExacte, Long valeurApproximative) {
super();

this.rang = rang;
this.valeurExacte = valeurExacte;
this.valeurApproximative = valeurApproximative;

this.approximation = Math.abs(valeurExacte - valeurApproximative);
}

/* hashcode / equals / tostring */

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((rang == null) ? 0 : rang.hashCode());
return result;
}

@Override
public String toString() {
return "FiboResult [rang=" + rang + ", valeurExacte=" + valeurExacte + ", valeurApproximative=" +
valeurApproximative + ", approximation=" + approximation + "]";
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
FiboResult other = (FiboResult) obj;
if (rang == null) {
if (other.rang != null)
return false;
} else if (!rang.equals(other.rang))
return false;
return true;
}

/* Getter et setter */

public Integer getRang() {
return rang;
}

public Long getValeurExacte() {
return valeurExacte;
}

public Long getValeurApproximative() {
return valeurApproximative;
}

public Long getApproximation() {
return approximation;
}

}

FiboBean.java

package com.dvp.fibowebapp;

import java.util.ArrayList;
import java.util.List;

import javax.faces.bean.ManagedBean;

@ManagedBean(name = "fiboBean")
public class FiboBean {

private static final Integer DEFAULT_RANG = 7;

private Integer rang;

private Long valeur;
private List<FiboResult> valeurs;

private final FiboService fiboService = FiboService.getInstance();

public void calculer() {
if(rang == null) {
return;
}

System.out.println("Calcul de la suite de Fibonacci pour le rang " + rang);

// Je calcule d'abord la liste.
valeurs = new ArrayList<FiboResult>(rang);
for (int i = 1; i <= rang; i++) {
final FiboResult fiboResult = calculerFiboResult(i);
valeurs.add(fiboResult);
}

// Puis la valeur pour le rang. Ici j'aurais pu optimiser, mais ce n'est
// pas l'objet de cet article.
valeur = fiboService.calculerFibonacci(rang);
}

private FiboResult calculerFiboResult(Integer rang) {
final Long valeurExacte = fiboService.calculerFibonacci(rang);
final Long valeurApproximative = fiboService.calculerApproximationfibonacci(rang);
final FiboResult fiboResult = new FiboResult(rang, valeurExacte, valeurApproximative);
return fiboResult;
}

/* Getters et setters */

public Integer getRang() {
return rang;
}

public void setRang(Integer rang) {
this.rang = rang;
}

public Long getValeur() {
return valeur;
}

public List<FiboResult> getValeurs() {
return valeurs;
}

public Integer getDefaultRang() {
return DEFAULT_RANG;
}

public List<FiboResult> getValeursInversees() {

final List<FiboResult> result = new ArrayList<FiboResult>();

for(int i = valeurs.size() - 1; 0 <= i; i--) {
result.add(valeurs.get(i));
}

return result;
}
}

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<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>
<groupId>com.dvp</groupId>
<artifactId>fibowebapp</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>

<name>fibowebapp</name>
<description>fibowebapp</description>

<licenses>
<license>
<name>Copyright ©1995-2012 thierryler.com et Copyright ©2012 Developpez.com</name>
<comments>Les sources présentées sur cette page sont libres de droits,  ...</comments>
</license>
</licenses>

<developers>
<!-- Thierry -->
<developer>
<name>Thierry Leriche-Dessirier</name>
<roles>
<role>Developper</role>
</roles>
<organization>ICAUDA</organization>
</developer>

</developers>

<properties>
<!-- Build -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.6</java.version>
<wtp.version>2.0</wtp.version>

<!-- Test -->
<junit.version>4.10</junit.version>

<!-- Servlet et pages -->
<mojarra.version>2.1.4</mojarra.version>
<jboss-el.version>2.0.1.GA</jboss-el.version>
<jstl.version>1.2</jstl.version>
<servlet-api.version>2.5</servlet-api.version>

<!-- Plugins -->
<maven-compiler-plugin.version>2.3.2</maven-compiler-plugin.version>
<maven-eclipse-plugin.version>2.8</maven-eclipse-plugin.version>
<tomcat-maven-plugin.version>1.1</tomcat-maven-plugin.version>

<!-- Pretty faces -->
<prettyfaces-jsf2.version>3.3.2</prettyfaces-jsf2.version>

<!-- JAX WS RT -->
<jaxws-rt.version>2.2.5</jaxws-rt.version>

</properties>

<dependencyManagement>
<dependencies>

<!-- JSF -->
<dependency>
<groupId>com.sun.faces</groupId>
<artifactId>jsf-api</artifactId>
<version>${mojarra.version}</version>
</dependency>

<dependency>
<groupId>com.sun.faces</groupId>
<artifactId>jsf-impl</artifactId>
<version>${mojarra.version}</version>
<scope>compile</scope>
</dependency>

<!-- JSTL -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>${jstl.version}</version>
</dependency>

<!-- Servlet 2.5 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>${servlet-api.version}</version>
<scope>provided</scope>
</dependency>

<!-- Test -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>

<!-- pretty faces -->
<dependency>
<groupId>com.ocpsoft</groupId>
<artifactId>prettyfaces-jsf2</artifactId>
<version>${prettyfaces-jsf2.version}</version>
</dependency>

<!-- JAX WS RT -->
<dependency>
<groupId>com.sun.xml.ws</groupId>
<artifactId>jaxws-rt</artifactId>
<version>${jaxws-rt.version}</version>
</dependency>

</dependencies>
</dependencyManagement>

<dependencies>

<!-- servlet -->
<dependency>
<groupId>com.sun.faces</groupId>
<artifactId>jsf-api</artifactId>
</dependency>

<dependency>
<groupId>com.sun.faces</groupId>
<artifactId>jsf-impl</artifactId>
<scope>compile</scope>
</dependency>

<!-- JSTL -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>

<!-- Servlet -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<scope>provided</scope>
</dependency>

<!-- pretty faces -->
<dependency>
<groupId>com.ocpsoft</groupId>
<artifactId>prettyfaces-jsf2</artifactId>
</dependency>

<!-- JAX WS RT -->
<dependency>
<groupId>com.sun.xml.ws</groupId>
<artifactId>jaxws-rt</artifactId>
</dependency>

</dependencies>

<build>
<finalName>fibowebapp</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-eclipse-plugin</artifactId>
<version>${maven-eclipse-plugin.version}</version>
<configuration>
<wtpversion>${wtp.version}</wtpversion>
<source>${java.version}</source>
<target>${java.version}</target>
<downloadSources>true</downloadSources>
<downloadJavadocs>true</downloadJavadocs>
</configuration>
</plugin>

<!-- Tomcat plugin for embedded tomcat -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>tomcat-maven-plugin</artifactId>
<version>${tomcat-maven-plugin.version}</version>
<configuration>
<path>/${project.build.finalName}</path>
</configuration>
</plugin>
</plugins>
</build>
</project>

FibonacciWebService.java

package com.dvp.fibowebapp.ws;

import javax.jws.WebParam;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;

import com.dvp.fibowebapp.FiboResult;
import com.dvp.fibowebapp.FiboService;

@WebService
@SOAPBinding(style = Style.RPC)
public class FibonacciWebService {

private final FiboService fiboService = FiboService.getInstance();

public Long fibonacci(@WebParam(name = "rang") Integer rang) {

Long result = fiboService.calculerFibonacci(rang);

return result;
}

public FiboDTO[] fibonacciList(@WebParam(name = "rang") Integer rang, @WebParam(name = "limit") Integer nb) {

int size = nb;
if (rang < nb) {
size = rang;
}

FiboDTO[] list = new FiboDTO[size];
for (int i = 0; i < size; i++) {
final FiboResult fiboResult = calculerFiboResult(rang - i);
list[i] = convert(fiboResult);
}

return list;
}

private FiboDTO convert(FiboResult fiboResult) {
FiboDTO fiboDTO = new FiboDTO();
fiboDTO.setApproximation(fiboResult.getApproximation());
fiboDTO.setRang(fiboResult.getRang());
fiboDTO.setValeurApproximative(fiboResult.getValeurApproximative());
fiboDTO.setValeurExacte(fiboResult.getValeurExacte());

return fiboDTO;
}

private FiboResult calculerFiboResult(Integer rang) {
final Long valeurExacte = fiboService.calculerFibonacci(rang);
final Long valeurApproximative = fiboService.calculerApproximationfibonacci(rang);
final FiboResult fiboResult = new FiboResult(rang, valeurExacte, valeurApproximative);
return fiboResult;
}

}

sun-jaxws.xml

<?xml version="1.0" encoding="UTF-8"?>
<endpoints xmlns="http://java.sun.com/xml/ns/jax-ws/ri/runtime"
version="2.0">

<endpoint name="fibonacci" implementation="com.dvp.fibowebapp.ws.FibonacciWebService"
url-pattern="/fibonacci" />
</endpoints>

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

<!-- JSF 2 IMPLEMENTATION -->
<context-param>
<param-name>javax.faces.DEFAULT_SUFFIX</param-name>
<param-value>.xhtml</param-value>
</context-param>
<!-- Enables special Facelets debug output during development -->
<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<param-value>Development</param-value>
</context-param>
<!-- Causes Facelets to refresh templates during development -->
<context-param>
<param-name>javax.faces.FACELETS_REFRESH_PERIOD</param-name>
<param-value>1</param-value>
</context-param>
<context-param>
<param-name>javax.faces.FACELETS_SKIP_COMMENTS</param-name>
<param-value>true</param-value>
</context-param>

<!-- Web service -->
<listener>
<listener-class>com.sun.xml.ws.transport.http.servlet.WSServletContextListener</listener-class>
</listener>
<servlet>
<servlet-name>WSServlet</servlet-name>
<servlet-class>com.sun.xml.ws.transport.http.servlet.WSServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>WSServlet</servlet-name>
<url-pattern>/fibonacci</url-pattern>
</servlet-mapping>

<!-- Pretty faces -->
<filter>
<filter-name>Pretty Filter</filter-name>
<filter-class>com.ocpsoft.pretty.PrettyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>Pretty Filter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>FORWARD</dispatcher>
<dispatcher>REQUEST</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>

<!-- Faces -->
<servlet>
<servlet-name>facesServlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>facesServlet</servlet-name>
<url-pattern>*.jsf</url-pattern>
</servlet-mapping>

<!-- Default page -->
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
</web-app>