Partie 1 : Développement Bottom-Up (Code First)

2. Création de la classe Test.java

Fichier src/mypackage/Test.java :

package mypackage;
 
import javax.jws.WebService;
import javax.jws.WebMethod;
 
@WebService
public class Test {
    
    @WebMethod
    public String echoBonjour(String name) {
        return "Bonjour " + name + ". Service Bottom-UP";
    }
}

6. Explication de la commande wsgen

La commande wsgen génère les artefacts JAX-WS nécessaires au déploiement du service web :

  • Analyse de la classe mypackage.Test annotée avec @WebService
  • Génération des classes wrapper pour les messages SOAP (requête/réponse)
  • Création des classes de marshalling/unmarshalling JAXB
  • Production des fichiers nécessaires à l’invocation du service

7. Classes générées

Dans le répertoire build/mypackage/jaxws/ :

  • EchoBonjour.class : Wrapper pour la requête
  • EchoBonjourResponse.class : Wrapper pour la réponse

Dans le répertoire src/mypackage/jaxws/ :

  • EchoBonjour.java : Classe représentant les paramètres d’entrée de la méthode
  • EchoBonjourResponse.java : Classe représentant la valeur de retour

EchoBonjour.java

package mypackage.jaxws;
 
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;
 
@XmlRootElement(name = "echoBonjour", namespace = "http://mypackage/")
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "echoBonjour", namespace = "http://mypackage/")
public class EchoBonjour {
 
    @XmlElement(name = "arg0", namespace = "")
    private String arg0;
 
    public String getArg0() {
        return this.arg0;
    }
 
    public void setArg0(String arg0) {
        this.arg0 = arg0;
    }
}

Encapsule le paramètre d’entrée de la méthode echoBonjour pour le transport SOAP.

EchoBonjourResponse.java

package mypackage.jaxws;
 
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;
 
@XmlRootElement(name = "echoBonjourResponse", namespace = "http://mypackage/")
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "echoBonjourResponse", namespace = "http://mypackage/")
public class EchoBonjourResponse {
 
    @XmlElement(name = "return", namespace = "")
    private String _return;
 
    public String getReturn() {
        return this._return;
    }
 
    public void setReturn(String _return) {
        this._return = _return;
    }
}

Encapsule la valeur de retour de la méthode pour la réponse SOAP.

11. Vérification du déploiement

Connexion à la console d’administration WildFly (http://localhost:9990/console) et navigation vers Deployments.

Le service myprojectTEST.war apparaît avec le statut Enabled.

a. Messages définit :

<message name="echoBonjour">
    <part name="parameters" element="tns:echoBonjour"/>
</message>
<message name="echoBonjourResponse">
    <part name="parameters" element="tns:echoBonjourResponse"/>
</message>

b. Méthodes disponibles :

<portType name="Test">
    <operation name="echoBonjour">
        <input message="tns:echoBonjour"/>
        <output message="tns:echoBonjourResponse"/>
    </operation>
</portType>

c. Protocole réseau :

<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>

d. Style d’interaction :

Le binding indique style="document"

e. Adresse du service :

<soap:address location="http://localhost:8080/myprojectTEST/Test"/>

12. Test avec SOAP UI

Création d’un nouveau projet SOAP dans SOAP UI avec le WSDL :

Requête de test :

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
                  xmlns:myp="http://mypackage/">
   <soapenv:Header/>
   <soapenv:Body>
      <myp:echoBonjour>
         <arg0>Claude</arg0>
      </myp:echoBonjour>
   </soapenv:Body>
</soapenv:Envelope>

Réponse obtenue :

<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
   <S:Body>
      <ns2:echoBonjourResponse xmlns:ns2="http://mypackage/">
         <return>Bonjour Claude. Service Bottom-UP</return>
      </ns2:echoBonjourResponse>
   </S:Body>
</S:Envelope>

13. -wsdl

L’option -wsdl demande à wsgen de générer également le fichier WSDL.

14. Artefacts générés

En plus des classes précédentes, les fichiers suivants sont créés dans build/ :

  • TestService.wsdl : Description WSDL complète du service
  • TestService_schema1.xsd : Schéma XML décrivant les types de données utilisés

Partie 2 : Développement Top-Down (Contract First)

3. Examen du fichier Test2Service.wsdl

Le WSDL définit deux opérations dans le portType Test2 :

<operation name="addition">
    <input message="tns:addition"/>
    <output message="tns:additionResponse"/>
</operation>
<operation name="sayhello">
    <input message="tns:sayhello"/>
    <output message="tns:sayhelloResponse"/>
</operation>
  • addition : Addition de deux entiers (arg0, arg1) → retourne un entier
  • sayhello : Salutation avec un nom (arg0 string) → retourne une chaîne

Test2Service_schema1.xsd

Le schéma définit les types complexes pour chaque opération :

  • addition : contient deux éléments arg0 et arg1 de type xs:int
  • additionResponse : contient un élément return de type xs:int
  • sayhello : contient un élément arg0 de type xs:string
  • sayhelloResponse : contient un élément return de type xs:string

5. wsimport

La commande wsimport lit le fichier WSDL et génère :

  • L’interface du service représentant le portType
  • Les classes JAXB pour les types de données du schéma
  • Les classes wrapper pour les messages SOAP
  • La classe Service pour obtenir les stubs clients
  • L’interface du port pour l’invocation du service

6. Classes Java générées

Dans src/mypackage/ :

Interfaces et classes de service :

  • Test2.java : Interface définissant les méthodes du service
  • Test2Service.java : Classe Service pour obtenir le port
  • Test2Port.java : Interface du port (similaire à Test2)

Classes JAXB pour les types :

  • Addition.java : Classe représentant la requête d’addition
  • AdditionResponse.java : Classe représentant la réponse d’addition
  • Sayhello.java : Classe représentant la requête sayhello
  • SayhelloResponse.java : Classe représentant la réponse sayhello
  • ObjectFactory.java : Factory JAXB
  • package-info.java : Informations du package

Test2.java

package mypackage;
 
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.ws.RequestWrapper;
import javax.xml.ws.ResponseWrapper;
 
@WebService(name = "Test2", targetNamespace = "http://mypackage/")
@XmlSeeAlso({
    ObjectFactory.class
})
public interface Test2 {
 
    @WebMethod
    @WebResult(targetNamespace = "")
    @RequestWrapper(localName = "addition", targetNamespace = "http://mypackage/", 
                    className = "mypackage.Addition")
    @ResponseWrapper(localName = "additionResponse", targetNamespace = "http://mypackage/", 
                     className = "mypackage.AdditionResponse")
    public int addition(
        @WebParam(name = "arg0", targetNamespace = "")
        int arg0,
        @WebParam(name = "arg1", targetNamespace = "")
        int arg1);
 
    @WebMethod
    @WebResult(targetNamespace = "")
    @RequestWrapper(localName = "sayhello", targetNamespace = "http://mypackage/", 
                    className = "mypackage.Sayhello")
    @ResponseWrapper(localName = "sayhelloResponse", targetNamespace = "http://mypackage/", 
                     className = "mypackage.SayhelloResponse")
    public String sayhello(
        @WebParam(name = "arg0", targetNamespace = "")
        String arg0);
}

C’est une interface Java qui définit le contrat du service.

7. Implémentation du service

Remplacement de Test2.java par l’implémentation concrète :

package mypackage;
 
import javax.jws.WebService;
import javax.jws.WebMethod;
 
@WebService
public class Test2 {
    
    private final String message = "Hello, ";
    
    @WebMethod
    public String sayhello(String name) {
        return message + name + " --- Test 2 top-down déploiement en ligne de commande";
    }
    
    @WebMethod(operationName="addition")
    public int add(int a, int b) {
        return (a + b);
    }
}

9. Déploiement

Le fichier Test2Service.war.deployed est créé, confirmant le déploiement.

10. Consultation du WSDL

Accès via la console d’administration ou directement :

http://localhost:8080/Test2Service/Test2?wsdl

Le WSDL affiché correspond au contrat défini initialement, avec les deux opérations addition et sayhello.

11. Test avec SOAP UI

Création d’un projet SOAP UI avec le WSDL :

http://localhost:8080/Test2Service/Test2?wsdl

Test de l’opération sayhello :

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
                  xmlns:myp="http://mypackage/">
   <soapenv:Header/>
   <soapenv:Body>
      <myp:sayhello>
         <arg0>World</arg0>
      </myp:sayhello>
   </soapenv:Body>
</soapenv:Envelope>

Réponse :

<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
   <S:Body>
      <ns2:sayhelloResponse xmlns:ns2="http://mypackage/">
         <return>Hello, World --- Test 2 top-down déploiement en ligne de commande</return>
      </ns2:sayhelloResponse>
   </S:Body>
</S:Envelope>

Test de l’opération addition :

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
                  xmlns:myp="http://mypackage/">
   <soapenv:Header/>
   <soapenv:Body>
      <myp:addition>
         <arg0>15</arg0>
         <arg1>27</arg1>
      </myp:addition>
   </soapenv:Body>
</soapenv:Envelope>

Réponse :

<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
   <S:Body>
      <ns2:additionResponse xmlns:ns2="http://mypackage/">
         <return>42</return>
      </ns2:additionResponse>
   </S:Body>
</S:Envelope>

Les deux opérations fonctionnent parfaitement !