Web services: première mise en œuvre

:!: Mise à jour bugfix simplestorecal et version SAAJ

Ce TP est à rendre pour le 14/11/2010 23:30 via spiral. Il faudra rendre un zip contenant les projets commentés. Il est également demandé de créer un ensemble de tests pour chaque fonctionnalité. Lorsque cela est possible, on s'appuiera sur JUnit (Voir ici) pour la mise en place des tests.

Il peut être utile pour déboguer d'utiliser TCPMon. Il s'agit d'une application graphique qui agit comme un proxy espion permettant de voir le contenu échangé avec un serveur.

Utilisation d'un service

Mise en place du service

Dans tous les cas s'assurer que c'est la version 6 du JDK qui est utilisée, par exemple en mettant les bonnes valeurs dans le PATH et dans JAVA_HOME

Une implémentation du service est disponible ici: simplestorecal.jar. (Sources: simplestorecal-src.zip) Pour lancer le service, il suffit d'utiliser la commande:

java -jar simplestorecal.jar

Les calendriers sont stockés dans un répertoire docs dans un fichier portant leur nom. L'adresse du service est http://localhost:8079/sw et le wsdl est accessible ici: http://localhost:8079/store-cal.wsdl.

Test avec soapUI

soapUI est une application permettant de tester des services. Installer soapUI ou le lancer avec Java Web Start. Créer un nouveau projet en spécifiant l'emplacement suivant pour le WSDL:http://localhost:8079/store-cal.wsdl (Disponible directement ici: store-cal.wsdl, XML Schema associé: simplecalendar.xsd). Par défaut, soapUI crée des requêtes de test à compléter pour chaque opération. Une fois le projet créé, éditer chaque requête pour remplir le contenu du message SOAP à envoyer. Modifier si besoin l'adresse du service sous la barre de titre. Lancer l'exécution des tests avec . Il est possible de combiner plusieurs requêtes dans un “TestCase”, lui même intégré dans une “TestSuite” par clic droit sur une requête. Pour passer des valeurs d'une réponse à la requête suivante, on peut utiliser un property transfert (qui par ailleurs est semblable à un assign en WS-BPEL). Créer un TestCase qui envoie un calendrier au service via storeCalOperation puis le récupère via getCalOperation.

Un programme pour gérer les calendriers

Projet Maven

Utiliser le projet maven préconfiguré suivant: clientsimple-src.zip. Ce projet dépend du projet du TP précédent.

On remplacera dans ce projet toutes les occurences de COQUERY par les noms des deux binômes (:!: bien utiliser les mêmes nom que dans le TP précédent, en particulier dans la dépendance). Il est très fortment conseillé de lire le pom.xml et de comprendre les différentes déclarations afin de pouvoir les modifier au besoin.

Remarque: si le projet du TP1 n'est pas trouvé par maven, il suffit normalement de l'installer en lançant

mvn install

depuis le répertoire du projet du tp1.

Récupération de calendrier

Ajouter la classe abstraite suivante à votre projet:

package m2ti.ti3.clientsimple;
 
import java.net.URL;
import javax.xml.transform.Source;
 
public abstract class CalendarRetriever {
 
    public abstract Source getCalendar(URL serviceEndpoint, String calendarName);
 
    public abstract int storeCalendar(URL serviceEndpoint, Source calendar);
 
    public static CalendarRetriever newInstance() {
        throw new UnsupportedOperationException("Non implementee");
    }
 
}

Étendre CalendarRetriever avec une classe concrète et renvoyer une nouvelle instance de cette classe au lieu de lever une exception dans newInstance.

La méthode getCalendar devra, étant donné un identifiant (String), récupérer le calendrier correspondant stocké dans le service storeCalService utilisé ci-dessus, via l'utilisation de l'opération getCalOperation. Pour ce faire, on utilisera au choix la bibliothèque Axis2 ou la bibliothèque SAAJ. Si cette dernière est utilisée, on pourra commenter la dépendance sur axis2 dans le fichier pom.xml car SAAJ est fournie avec le JDK 1.6.

:!: Le service simplestorecal fonctionne en SOAP 1.2. Pour forcer à utiliser cette version avec SAAJ, il faut créer le message factory comme suit:

factory = MessageFactory.newInstance(SOAPConstants.SOAP_1_2_PROTOCOL);

On créera ensuite une application Java (i.e. une méthode main dans la classe App) qui utilisera la méthode précédente pour au choix (en fonction des arguments en ligne de commande):

  • afficher le calendrier sur la sortie standard (option par défaut)
  • stocker le résultat dans un fichier xml (dont le nom est passé en argument de la ligne de commande)

Pour générer le .jar à exécuter:

mvn package

Ensuite, pour lancer l'application:

java -jar target/ClientSimple-1.0-SNAPSHOT-jar-with-dependencies.jar

Pour implémenter la méthode storeCalendar, dans le cas de l'utilisation de SAAJ, l'insersion du calendrier dans le message doit se faire par copie. Il existe pour cela la classe javax.xml.soap.SAAJResult qui pourra être utilisée comme réceptacle de la copie. On peut par exemple s'inspirer du code suivant:

public static int invokeStore(String name, Source cal, URL endpoint) {
...
  SOAPElement mainEl = body.addBodyElement(StoreCalConstants.STORE_CAL_INPUT_EL);
...  
  SAAJResult mainElRes = new SAAJResult(mainEl);
  Transformer copy = TransformerFactory.newInstance().newTransformer();
  copy.transform(cal, mainElRes);
...
}

Modifier l'application afin de pouvoir prendre un nom de fichier de calendrier ical et optionnellement un nom à associer au calendrier en arguments de la ligne de commande et utilisera le service pour stocker le calendrier.

Client sur serveur d'application

Utiliser l'archive calendarwebapp-src.zip pour comme base pour un nouveau projet Maven.

Ajouter la dépendance maven correspondant au projet ClientSimple avec la bonne version.

Lors du développement de projets Web et/ou de service webs, il est conseillé d'utiliser des bibliothèques de logging (comme Log4j ou les classes du package java.util.logging) pour le deboggage.

Un fichier de propriétés

Dans Other Sources/resources1), créer un fichier calwebapp.properties contenant ce qui suit:

calservice.endpointurl=http://localhost:8079/sw

Il est ensuite possible de récupérer les informations stockées dans ce fichier via un objet java.util.Properties qui va récupérer ces informations dans fichier via la méthode load2). Ce fichier sera utilisé pour récupérer l'adresse du service.

Une servlet qui s'interface avec le service

Ajouter la dépendance suivante à votre projet3):

    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>servlet-api</artifactId>
        <version>2.4</version>
        <scope>provided</scope>
    </dependency>

Créer une nouvelle servlet ViewCalendar dans le projet4), dans laquelle on implémentera la méthode processRequest(HttpServletRequest request,HttpServletResponse response). Cette servlet aura le comportement suivant:

  • récupérer la valeur du paramètre calno (via request.getParameter(…))
  • appel a l'opération getCalOperation du web service storeCalService en utilisant la valeur de calno.
  • si tout va bien:
    • envoi d'un header “Content-type: text/xml” via la méthode response.setContentType(“text/xml”)
    • envoi du fichier XML représentant le calendrier via son écriture sur response.get.getOutputStream()
  • Sinon:
    • envoi d'un content-type “text/html”
    • écriture sur response.getWriter() d'une page HTML décrivant l'erreur

Pour lancer l'application, utiliser

mvn tomcat:run -Dmaven.tomcat.port=8081

Remarque: cette commande lance l'application sur le port 8081, ce qui évite un conflit avec un serveur d'application lancé sur le port 8080.

Tester ensuite la servlet via une URL du type http://localhost:8081/CalendarWebApp/ViewCalendar?calno=0 5).

Remarque: Cette servlet constitue un premier exemple de service Web “léger”.

Quelques évolutions

Modifier la servlet pour obtenir le comportement suivant, en fonction de la valeur du paramètre type:

  • xml comportement précédent
  • html renvoie le formattage HTML du calendrier (c.f. TP 1). Le content-type doit être “text/html”.
  • rss renvoie le formattage RSS du calendrier (c.f. TP 1). Le content-type doit être “application/rss+xml”.

Tester avec comme précédement avec votre navigateur Web.

1)
i.e. src/main/resources
2)
On chargera ce fichier via le ClassLoader
3)
scope: provided indique que le jar sera en pratique fourni par l'environnement d'exécution et qu'il n'y a donc pas lieu de le placer dans le .war
4)
ne pas oublier de spécifier un package pour la servlet
5)
on peut remplacer 0 par tout numéro de calendrier valide