Mise en œuvre de services Web via le framework Ellipse

Ellipse Framework est une solution de développement d'applications Web à base de technologies Java et JavaScript. Le but de ce framework est d'optimiser votre productivité lors de la mise en œuvre de vos applications Web. Pour ce faire, un grand nombre d'éléments logiciels vous sont directement proposés par le framework afin d'adresser les principales problématiques de la mise en œuvre d'une application Web. Si vous choisissez le framework Ellipse pour vos développements d'applications Web en Java, il ne vous sera plus nécessaire de chercher à intégrer un certain nombre de solutions distinctes (un framework de développement Web en Java, un moteur de services Web, une API JavaScript complémentaire...) étant donné que le framework Ellipse cherche à répondre à cette problématique.

Parmi les principaux aspects traités par le framework, nous pouvons citer : concept de pages Web, de composants Web réutilisables et de services Web, API côté serveur en Java, API côté client en JavaScript, documentations Java/JavaScript fusionnées, composants Web évolués (DataGrid, histogrammes graphiques à partir de modèle de données, camemberts...), outils d'aide au débogage (moteur de traces), moteur de recherche intégré, moteur de statistiques de navigation... Notez aussi qu'un plugin pour l'EDI Eclipse a été développé afin de faciliter l'utilisation du framework : le plugin Ellipse. Ellipse Framework, ainsi que son plugin sont développés par la société Infini Software.

L'objectif de ce tutoriel est de vous montrer comment créer des services Web en utilisant le framework Ellipse. Certes, Java SE propose déjà un certain support pour la mise en œuvre de services Web, mais le framework Ellipse propose quelques mécanismes supplémentaires permettant notamment de simplifier le déploiement de vos services Web sur un serveur compatible Java EE. Bien entendu, nous allons utiliser le plugin Ellipse afin de nous simplifier la construction de ces éléments.

Pour réagir à ce tutoriel, un espace de dialogue vous est proposé sur le forum 3 commentaires Donner une note à l'article (5)

Article lu   fois.

L'auteur

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

I. Concepts généraux

Un service Web (ou Web service, en anglais) est un objet hébergé par un serveur HTTP sur lequel il est possible d'invoquer des méthodes à distance. Chaque appel de méthode est réalisé en transportant la valeur des paramètres via une requête HTTP (donc, du poste client vers le serveur HTTP) et en transportant la valeur de retour de la méthode distante considérée via une réponse HTTP (du serveur vers le client). Une autre caractéristique des services Web réside dans l'interopérabilité de la technologie : qu'il s'agisse du code client ou du service Web, ils peuvent tous les deux être développés via différentes technologies (Java, .Net, PHP...).

En fait, la technologie relative aux services Web est une recommandation du W3C (World Wide Web consortium : http://www.w3.org). Le W3C est un consortium réunissant de multiples entreprises ayant un intérêt à promouvoir et à faire développer les technologies du Web. La recommandation est le niveau le plus abouti dans le processus de standardisation du W3C. Les services Web représentent donc une technologie mature : en tant que telle, elle est notamment supportée par le Java SE 6.0.

L'intérêt de cette technologie est de mettre les données présentes sur le Web à disposition de personnes physiques (via les pages Web) mais aussi de programmes (via les services Web). On peut donc imaginer deux serveurs Web, pour deux entreprises différentes, échangeant des données via cette technologie dans le but de produire une unique proposition commerciale intégrant des informations des deux entreprises considérées. Dans un tel cas les deux serveurs échangent l'information par de simples appels de méthodes (donc, avec des paramètres et des valeurs de retour) sur des objets de type "service Web".

L'intérêt de faire héberger vos services Web par un serveur HTTP réside dans le fait que par défaut, les requêtes/réponses réseaux passent par le port 80. Si entre le client qui émet la requête et le serveur qui fournit le service, l'infrastructure réseau utilisée met en jeux des firewalls ou des proxys HTTP, cela ne posera à priori aucun problème car sur ces systèmes, le port 80 est normalement ouvert. Notez aussi que l'utilisation de services Web peut permettre de bâtir une architecture SOA (Service Oriented Architecture).

II. SOAP (Simple Object Access Protocol) et WSDL (Web Service Description Language)

Avec les services Web, les requêtes et les réponses HTTP contiendront des informations structurées via la syntaxe XML (elle aussi étant une recommandation du W3C). N'oubliez pas que XML est un méta langage : il sert à produire des langages adaptés à vos besoins, mais basés sur une syntaxe à base de tags.

Deux langages XML (on parle aussi de grammaires XML) sont très importants pour la compréhension du fonctionnement des services Web. Il s'agit de SOAP (Simple Object Access Protocol) et de WSDL (Web Service Description Language).

SOAP permet de structurer les données qui vont être échangées entre l'utilisateur du service et le fournisseur (le service Web). Bien qu'on puisse envisager d'autres alternatives à XML, ce choix permet de facilement garantir l'interopérabilité. Effectivement, il existe des parseurs XML sur quasiment toutes les plates-formes (Solaris, Linux...) et pour tous les langages (Java, C++, PHP...).

L'intérêt de WSDL est un petit peu plus subtil à cerner. Disons, pour simplifier que les deux équipes qui vont développer le service Web et le code du consommateur du service, n'ont pas l'obligation de se connaître. Elles peuvent, qui plus est, être localisées n'importe où sur le globe, cela ne gênera pas pour le bon fonctionnement du modèle. Or, un appel de méthode sur un objet distant, dans l'absolu, ne veux strictement rien dire : si on descend au niveau du code machine, on peut dire qu'un appel de méthode ne peut fonctionner qu'au sein d'un même processus (du moins pour les processeurs modernes). Donc, l'appel au niveau de l'application cliente est réalisé entre votre code et un représentant local du service Web. Ce représentant local (souvent appelé proxy - à ne pas confondre avec les proxy HTTP) nous permet de "simuler" l'appel distant dans le sens ou il se comporte comme l'objet distant. Il fourni exactement les mêmes méthodes, mais leurs implémentations se chargent de réaliser la communication HTTP. La question est de savoir comment on génère ce représentant local. C'est là qu'intervient le WSDL : cette description des méthodes accessibles via ce service Web servira à un outil (wsimport avec le Java SE 6.0) pour générer le proxy. Qui plus est, le WSDL peut être récupéré via une simple requête HTTP sur le service. Donc, oui, les deux équipes de développement peuvent ne pas se connaître et ne pas avoir discuté sur la manière utiliser le service Web considéré.

III. Présentation de L'API JAX-WS

Historiquement parlant, la première API ayant permis le développement de services Web avec le langage Java fut JAX-RPC. Ce modèle était relativement lourd à mettre en œuvre et n'utilisait pas les dernières technologies objets introduites dans le Java SE 5.0 (je pense, bien entendu, aux annotations Java). Ces considérations ont abouti à produire un second modèle de mise en œuvre de services Web.

Il est donc maintenant préférable d'utiliser l'API JAX-WS (Java Api for Xml - Web Services). Cette API est notamment localisée dans le package javax.jws. Si vous prenez soin d'ouvrir la Javadoc sur ce package, vous vous apercevrez qu'elle est constituée d'un certain nombre d'annotations (javax.jws.WebService et javax.jws.WebMethod notamment). Cela induit le fait que la nouvelle API de mise en œuvre de services Web est très simple d'emploi : il suffit de coder une classe Java traditionnelle et de lui adjoindre un certain nombre d'annotations pour qualifier les méthodes qui seront accessibles via l'extérieur.

À titre d'exemple, nous allons considérer une application de chat en ligne accessible via le Web. Cette application est découpée en deux parties bien distinctes : la console cliente, permettant d'afficher les messages échangés et le composant serveur faisant office de salle de discussion. C'est sur cette dernière partie que nous allons commencer à porter notre attention. La mise en œuvre, vous allez vous en rendre compte, est relativement simple. Une seule classe de type service Web va nous suffire pour coder la partie serveur. Nous appellerons cette classe ChatRoomServiceImpl.

Cette classe, va comporter cinq méthodes accessibles via HTTP: subscribe, unsubscribe, sendMessage, getMessages et getUsers. Voici un descriptif rapide de la responsabilité de chacune des ces méthodes.

  • @WebMethod public void subscribe( String pseudo ) : cette méthode permet de s'inscrire à la salle de discussion considérée. Effectivement, HTTP est un protocole déconnecté et, qui plus est, l'architecture Web ne permet pas d'envoyer une information au navigateur (du moins à l'initiative du serveur HTTP) : c'est donc l'application cliente qui doit périodiquement interroger la salle de discussion pour savoir si de nouveaux messages ont été reçus. La salle de discussion doit donc, pour chaque utilisateur, mémoriser les nouveaux messages qui ont été reçus. Dans le système, un utilisateur sera identifié par son pseudo.
  • @WebMethod public void unsubscribe( String pseudo ) : à l'inverse de la précédente, cette méthode permet de désinscrire une personne de la salle de discussion. À partir de là, il n'est plus nécessaire de mémoriser les nouveaux messages pour cet utilisateur.
  • @WebMethod public void sendMessage( String pseudo, String message ) : cette méthode est utilisée par le client pour lui permettre d'envoyer une message à la salle de discussion. Cette méthode accepte deux paramètres : le pseudo et le message à proprement parler.
  • @WebMethod public ArrayList getMessages( String pseudo ) : cette méthode permet de pouvoir retrouver l'ensemble des messages reçus par cet utilisateur depuis la précédente invocation de la méthode getMessages. Cette méthode sera invoquée périodiquement.
  • @WebMethod public ArrayList getUsers() : permet de retrouver tous les utilisateurs connectés à la salle de discussion. Cette méthode sera invoquée périodiquement.

Voici le code complet de la classe de salle de discussion. Notez l'utilisation des annotations JAX-WS. Notez aussi qu'une méthode statique main est adjointe : elle permet de lancer le service Web en stand-alone sans forcément nécessiter de serveur HTTP. Cela est fort pratique pour tester le service Web.

Un chat sous forme de service Web
Sélectionnez
01 package corelib.services.web.samples.webservices;
02
03 import java.util.ArrayList;
04 import java.util.Hashtable;
05
06 import javax.jws.WebMethod;
07 import javax.jws.WebService;
08 import javax.xml.ws.Endpoint;
09
10 @WebService(serviceName = "ChatRoomService", name = "ChatRoom")
11 public class ChatRoomServiceImpl {
12
13     private Hashtable<String, ArrayList<String>> userMessages =
14                 new Hashtable<String, ArrayList<String>>();
15
16     @WebMethod public void subscribe( String pseudo ) {
17         sendMessage( "ChatRoom", "User " + pseudo + " connected" );
18         userMessages.put( pseudo, new ArrayList() );
19     }
20
21     @WebMethod public void unsubscribe( String pseudo ) {
22         userMessages.remove( pseudo );
23         sendMessage( "ChatRoom", "User " + pseudo + " disconnected" );
24     }
25
26     @WebMethod public void sendMessage( String pseudo, String message ) {
27         String fullMessage = pseudo + " >>> " + message;
28         System.out.println( fullMessage );
29         for ( ArrayList<String> array : userMessages.values() ) {
30             array.add( fullMessage );
31         }
32     }
33
34     @WebMethod public ArrayList<String> getMessages( String pseudo ) {
35         if ( pseudo == null ) return null;
36         ArrayList<String> messages = (ArrayList) userMessages.get( pseudo );
37         if ( messages == null ) return null;
38         userMessages.put( pseudo, new ArrayList() );
39         return messages;
40     }
41
42     @WebMethod public ArrayList<String> getUsers() {
43         ArrayList<String> users = new ArrayList();
44         if ( users == null ) return null;
45         for( String user : userMessages.keySet() ) users.add( user );
46         return users;
47     }
48
49     public static void main( String[] args ) {
50         // For standalone tests
51         Endpoint.publish( "http://localhost:8080/webapp/simple", new ChatRoomServiceImpl() );
52     }
53
54 }

Attention : ce code est un prototype : il pourrait sans aucune difficulté être amélioré pour permettre un fonctionnement encore plus poussé. Par exemple, avec cette implémentation, si deux utilisateurs se connectent avec exactement le même pseudo, les choses risquent de ne pas bien se passer.

IV. Déploiement d'un service Web dans une application Web

Pour déployer le service Web sur un serveur HTTP (Tomcat en l'occurrence), deux dernières étapes sont nécessaires. La première consiste à rajouter une configuration dans le fichier WEB-INF/web.xml. Le framework Ellipse gère notamment deux types d'éléments Web : les pages Web (d'extension .wp) et les services Web (d'extension .ws). Les extensions proposées ne sont absolument pas imposées : si vous souhaitez les changer, vous le pouvez. Vous pourriez même faire en sorte que ces deux types de composants utilisent une même extension. Mais, la proposition qui vous est faite a l'avantage de nous rappeler immédiatement la nature du fichier auquel nous avons à faire. Voici donc la configuration minimale permettant l'invocation d'un service Web (voir lignes 19 à 22).

Fichier WEB-INF/web.xml
Sélectionnez
01 <?xml version='1.0' encoding='UTF-8'?>
02 <!DOCTYPE web-app PUBLIC
03   "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
04   "http://java.sun.com/dtd/web-app_2_3.dtd">
05 <web-app>
06 
07     <!-- Begin of file -->
08 
09     <servlet>
10         <servlet-name>Ellipse Servlet</servlet-name>
11         <servlet-class>corelib.services.web.webapplications.ControllerServlet</servlet-class>
12     </servlet>
13 
14     <servlet-mapping>
15         <servlet-name>Ellipse Servlet</servlet-name>
16         <url-pattern>*.wp</url-pattern>
17     </servlet-mapping>
18 
19     <servlet-mapping>
20         <servlet-name>Ellipse Servlet</servlet-name>
21         <url-pattern>*.ws</url-pattern>
22     </servlet-mapping>
23 
24     <!-- End of file -->
25 
26 </web-app>

La seconde étape consiste à définir le fichier d'extension .ws qui servira de point d'invocation du service Web (on parle de "end point"). Ce fichier ressemble, d'une certaine manière, à une page Web Ellipse dans le sens ou il référence la classe de Web service à utiliser. À terme, le framework Ellipse devrait permettre de rajouter d'autres informations dans ce fichier.

Fichier ChatRoom.ws
Sélectionnez
01 <?xml version="1.0" encoding="ISO-8859-1" ?>
02 <web:Service xmlns:web="corelib.services.web.webservices"
03           	 codeBehind="corelib.services.web.samples.virtualcaddy.webservices.ChatRoomServiceImpl" />

Vous pouvez maintenant déployer votre application Web sur votre serveur HTTP. Afin de tester que le service Web est correctement déployé, vous pouvez invoquer l'URL suivante : http://localhost:8080/VirtualCaddy/ChatRoom.ws?wsdl. Si tout ce passe bien, le WSDL de votre service devrait vous être retourné.

Pour ceux qui auraient déjà testé certaines solutions de déploiement de services Web (avec Metro sous Tomcat par exemple), notez un point remarquable : les générations du proxy serveur ainsi que du WSDL (normalement réalisé via l'outil wsgen fournit par le Java SE) sont ici complètement automatisées. C'est lors de la première invocation du service Web que les informations manquantes seront produites. Il en découle un point important : pour fonctionner, Ellipse a besoin d'un Java SE 6.0 (pas d'un JRE) sans quoi l'outil de production wsgen ne serait pas disponible.

V. Utilisation du plugin Ellipse pour produire un nouveau service Web

Comme nous venons de le voir, un minimum de deux fichiers sont utiles pour la mise en œuvre d'un service Web : la classe d'implémentation du service et le fichier XML définissant l'URL d'attaque du service. Vous pouvez produire ces deux fichiers en une seule manipulation si vous utilisez le plugin Ellipse (un plugin s'intégrant sur l'IDE Eclipse). Pour ce faire, placez-vous dans l'explorateur de paquetages de votre Eclipse, cliquez avec le bouton droit de la souris et sélectionner "New", puis "Web Service". Une boîte de dialogue devrait s'ouvrir : en voici une capture d'écran.

Assistant de création d'un nouveau service Web Ellipse.
Assistant de création d'un nouveau service Web Ellipse.

Renseignez-y correctement les informations relatives de votre nouveau service Web et vos deux fichiers devrait être correctement créés.

VI. Appel d'un service Web en Java

La première chose à faire pour pouvoir coder notre application cliente est de générer le proxy client. Pour ce faire, le Java SE 6.0 met à notre disposition l'outil wsimport. Cet outil prend en paramètre de ligne de commande l'adresse Web du WSDL de votre service. La ligne de commande suivante devrait donc vous permettre de produire ce proxy. Notez bien que ce sont directement les fichiers .class qui seront produits (vous pourriez aussi demander à obtenir les .java : option -keep).

Génération du proxy client via la commande wsimport
Sélectionnez
$> wsimport http://localhost:8080/VirtualCaddy/ChatRoom.ws?wsdl

Ensuite il vous faut coder votre application cliente. Dans l'exemple ci-dessous, nous nous contentons de nous inscrire à la salle de discussion, d'envoyer un message, de demander tous nos messages disponibles, de lister les utilisateurs connectés et enfin de nous désinscrire de la salle de discussion (le tout séquentiellement).

Exemple d'utilisation d'un service Web à partir de Java
Sélectionnez
 01 import corelib.services.web.samples.virtualcaddy.webservices.*;
02 import java.util.*;
03
04 public class Client {
05
06     public static void main( String [] args ) {
07
08         ChatRoom room = new ChatRoomService().getChatRoomPort();
09         room.subscribe( "Donald" );
10         List users = room.getUsers();
11         for( Object user : users ) System.out.println( user );
12         room.sendMessage( "Donald", "Trop fort" );
13         List messages = room.getMessages( "Donald" );
14         for( Object message : messages ) System.out.println( message );
15         room.unsubscribe( "Donald" );
16
17     }
18
19 }

Vous pouvez maintenant compiler votre application cliente et l'exécuter. Normalement elle devrait se connecter correctement à votre service Web. Et vous devriez vous passer des messages dans les logs du serveur HTTP utilisé. Dans un prochain tutoriel nous verrons comment utiliser ce service Web au travers d'une IHM basée sur HTML/JavaScript en utilisant le framework Ellipse : effectivement, le framework propose une API permettant l'appel de services Web directement à partir de JavaScript.

VII. Échange d'objets via un service Web

Les services Web permettent aussi d'échanger des paramètres (ainsi qu'une valeur de retour de méthode) de type objet. Pour ce faire, les classes utilisées pour les données échangées doivent fournir un constructeur par défaut. Si ce n'est pas le cas, une exception sera déclenchée. À titre d'exemple, voici un objet de catalogue distant qui pourrait permettre de manipuler des instances d'une classe d'articles.

Classe corelib.services.web.samples.virtualcaddy.webservices.CatalogBrowserServiceImpl
Sélectionnez
01 package corelib.services.web.samples.virtualcaddy.webservices;
02
03 import javax.jws.WebMethod;
04 import javax.jws.WebService;
05
06 import corelib.services.web.samples.virtualcaddy.business.Article;
07 import corelib.services.web.samples.virtualcaddy.business.ArticleHome;
08
09
10 @WebService(serviceName = "CatalogBrowserService", name = "CatalogBrowser")
11 public class CatalogBrowserServiceImpl {
12
13     @WebMethod
14     public Article [] getAllArticles() {
15         return ArticleHome.findAll();
16     }
17
18     @WebMethod
19     public Article getArticle( int idArticle ) {
20         return ArticleHome.findByPrimaryKey( idArticle );
21     }
22
23 }

Il faut bien comprendre que le service Web pourra être utilisé par un autre langage que Java (.NET, Javascript, ...). La terminologie d'échange d'objets est donc peut être un peu exagérée. En fait, seules les données des objets seront transférées entre le client et le service Web (et non les méthodes, dont le code est spécifique à un environnement d'exécution). L'application cliente cherchera donc à représenter les objets du sevices Web, via des types similaires, mais qui exposeront seulement les propriétés publiques des objets serveurs.

VIII. Remerciements

Merci à Mickeal Baron d'avoir cru en Ellipse Framework et de nous avoir permis de publier nos tutoriels sur "Developpez.com".

Merci à Jacques Jean pour sa relecture orthographique.

Merci à tous ceux qui font confiance à Ellipse Framework.

L'équipe Ellipse.

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

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 developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.