Skip to main content

Interopérabilité REST : Accès à une logique métier Java depuis un client Silverlight

 

Article écrit le 4 mars 2009 par Stève Sfartz, Architecte Système d'Information

 

 

Sommaire

IntroductionIntroduction

Conception de l’API RestConception de l’API Rest

Implémentation au travers du framework RestlestImplémentation au travers du framework Restlest

Test de nos services restTest de nos services rest

Appel des services web depuis silverlight Appel des services web depuis silverlight

Constitution de l’interface SilverlightConstitution de l’interface Silverlight

Exécution des codes accompagnant cet articleExécution des codes accompagnant cet article

RessourcesRessources

 

Introduction

La technologie Silverlight 2 permet d’intégrer des données dynamiquement grâce à l’appel de Services Web  de communication de type REST et SOAP. Au cours de cet article, nous illustrerons un scénario d’interopérabilité où une application Web Riche Silverlight fera appel à des services Web REST, développés à l’aide du framework opensource Java Restlet. Dans un second temps, nous présenterons comment exécuter le projet dans l’environnement Eclipse grâce à l’extension Eclipse Tools for Silverlight.

Figure 1 : Copie Ecran de l’application Silverlight illustrée dans cet article

 

Conception de l’API REST

Tout d’abord, attachons nous à développer la logique métier. Dans le cadre de notre exemple, il s’agit de proposer une liste de clients, d’accéder aux informations détaillées d’un client et de proposer à la mise à jour ou la suppression d’une fiche client. De plus, il faudra être capable de filtrer la liste en fonction du pays sélectionné.

Une conception REST de l’application nous amène naturellement à isoler la ressource Client. Les URI suivantes seront proposées :

URI

HTTP

Description

/customers/

GET

Retourne la liste des références vers des clients

/customers/{id}

GET

Retourne le client dont l’ID est spécifié

/customers/ ?country=France

GET

Retourne la liste des clients résidents en France

/customers/{id}

PUT

Modifie le client avec les valeurs spécifiées via le flux XML d’entrée

/customers/{id}

DELETE

Supprime le client

/customers/

POST

Crée un nouveau client avec les valeurs spécifiées via le flux XML d’entrée

/customers/?expand=true

GET

Retourne la liste des références vers les clients ainsi que les propriétés pour chaque client

Figure 2 : Conception des URI : deux ressources « Client » et « Liste de clients »

Remarque : par soucis d’optimisation, nous avons ajouté une URI comprenant l’extension « expand ». Cette URI permet de développer le graphe de clients à partir de l’accès à la liste complète des clients, ainsi nous retournerons le flux en figure X depuis l’invocation de l’URL … plutôt que le flux situé en figure Y. En effet, ce dernier nécessiterait d’être développé par des requêtes complémentaires (1 accès plutôt que N+1 accès où N est égal au nombre de clients affichés par l’interface Silverlight).

 

Implémentation au travers du framework Restlet

Le framework Restlet pour Java intègre nativement les concepts REST au niveau de son architecture. Ainsi, l’implémentation du scénario présenté précédemment se traduit par la création des ressources Client (« Customer ») et Liste de Clients (« Customers »).

Pour chacune de ces ressources, nous exposerons des représentations au format XML, et nous autoriserons la soumission de flux XML. Pour ce faire, nous déclarons supporter le MediaType TEXT_XML, et nous déclarons les ressources modifiables, c’est-à-dire, nous serons invoqués lors des méthodes HTTP POST, PUT et DELETE. Pour la génération du flux XML, nous avons choisi d’utiliser l’API DOM de Java. Ci-après un code source permettant de tenir compte d’une modification client.

public void storeRepresentation(Representation entity)
            throws ResourceException 
{

       DomRepresentation dr = new DomRepresentation(entity);
       Node node = dr.getNode("//Customer/CustomerId");
       String id = node.getTextContent();

       node = dr.getNode("//Customer/ContactName");
       String name = node.getTextContent();

       node = dr.getNode("//Customer/Country");
       String country = node.getTextContent();

       node = dr.getNode("//Customer/Company");
       String company = node.getTextContent();

       // Now, let's update the customer properties
       getCustomer().setID(id);
       getCustomer().setName(name);
       getCustomer().setCountry(country);
       getCustomer().setCompany(company);
}

Remarque : au niveau du code source Java qui accompagne cet article, vous remarquerez que nous avons choisi de maintenir la liste des clients en mémoire de façon à simplifier le code.

Il nous reste maintenant à exposer ces ressources au travers d’URI. Le framework Restlet permet de réaliser ces mappings au travers d’attachements, sachant que le moteur d’exécution peut être soit un serveur Web (Tomcat notamment, l’activation ayant lieu grâce à une Servlet), soit un conteneur léger proposé dans le framework (qui peut aussi faire office de serveur Web). Dans l’exemple joint à cet article, nous avons opté pour le conteneur léger (mode « self hosting »).

public synchronized Restlet createRoot() {
       // Create a router Restlet that defines routes.
       Router router = new Router(getContext());

       // Defines a route for the resource List of Customers
       router.attach("/customers/", CustomersResource.class);

       // Defines a route for the resource List of Customers
       router.attach("/customers/{id}", CustomerResource.class);

       return router;
}

Test de nos Services REST

Nos services sont désormais opérationnels. Nous pouvons les tester au travers de l’invocation des URI depuis un browser Web pour les méthodes GET. Pour télécharger et exécuter les codes accompagnant cet exemple, reportez vous à la section « Exécution » de l’article.

Pour ce qui est des ordres POST, PUT et DELETE, nous devons utiliser un outil qui soumettra nos flux XML. L’outil Fiddler fait référence dans ce domaine, il est téléchargeable à cette adresse : http://www.fiddlertool.com/fiddler/.

Par défaut, Fiddler intercepte les flux HTTP en se positionnant comme proxy. Cette fonctionnalité nécessite d’être paramétrée pour certains navigateurs et frameworks.

Figure 3 : Visualisation d’une méthode GET avec Fiddler

Figure 4 : Soumission d’un flux XML pour créer une ressource

Remarque : il est possible de faire un drag & drop d’une requête interceptée par Fiddler depuis la liste située sur la gauche vers l’onglet « Request Buidler ».

 

Appel des Services Web depuis Silverlight

Afin d’invoquer les Services REST créés précédemment, Silverlight propose la classe WebClient qui permet d’invoquer une URI et récupérer le flux sortant. Ces invocations sont asynchrones de sorte à ce que le rendu graphique soit indépendant des temps de latence réseau. Ainsi un code d’invocation d’un Service REST peut être décrit comme suit :

  1. Préparation de la requête, affectation du handler asynchrone
  2. Invocation du service REST
  3. Récupération du résultat

Le code attaché à cet article propose un pattern d’implémentation qui permet de regrouper l’ensemble du code invocation / traitement du résultat au sein d’un segment de code bien identifiable. Ce pattern est intéressant pour les aspects maintenance.

public void run()
{
     // Disable Button
      container.load.IsEnabled = false;

     // Build URL with Filter
     string requestURI = "http://localhost:8182/customers/?expand=true";
     string filter = container.country.Text;
     if (!String.IsNullOrEmpty(filter))
      {
          requestURI += "&country=" + filter;
      }

     var client = new WebClient();
     client.DownloadStringCompleted += new DownloadStringCompletedEventHandler (client_DownloadStringCompleted);
     client.DownloadStringAsync(newUri(requestURI));
}

void client_DownloadStringCompleted(object s, DownloadStringCompletedEventArgs e)
{
    string reponse = e.Result;
    IEnumerable<Customer> customers = null;
     if (e.Error == null)
     {
         XDocument doc = XDocument.Parse(reponse);
         customers = from customer in 
                                     doc.Elements("Customers").Elements("Customer")
                                     select new Customer
                                    {
                                    CustomerId = customer.Element("CustomerId").Value.ToString(),
                                    ContactName = customer.Element("ContactName").Value.ToString(),
                                    Country = customer.Element("Country").Value.ToString(),
                                    Company = customer.Element("Company").Value.ToString()
                                    };
     }
     container.list.ItemsSource = customers;

     // Enable Button
     container.load.IsEnabled = true;
}

Pour finaliser notre exemple, il nous faut néanmoins prendre en compte deux importantes limitations de la technologie Silverlight, qui se voit imposée les contraintes inhérentes aux plugins des navigateurs Web. Si vous souhaitez investiguer ces contraintes, nous avons détaillé ces aspects lors de l’évènement « Rendez-vous de l’interopérabilité Silverlight » figurant dans la section Ressources.

Limitation 1 : Invocations HTTP restreintes aux méthodes GET et POST.

 Cette limitation est suffisamment répandue pour que le framework Restlet l’ait prise en compte et intègre par défaut la possibilité de surcharger une méthode POST au travers du paramètre d’URL « ?method=<PUT|DELETE> ».

Limitation 2 : Politique d’invocation Cross Domain

Alors que notre application Silverlight est mise à disposition au travers d’un site Web accessible à partir de l’adresse http://localhost:8183. Pour pouvoir être consommés en Silverlight, il est nécessaire de configurer la sécurité d’accès par le client Silverlight aux Services REST. Ceci est obligatoire lorsque les services accédés ne sont pas situés sur le site d’origine de l’application Silverlight. Dans ce cas, il est nécessaire de déclarer une politique d’accès cross-domain qui définit des autorisations d’accès. Nous avons donc déclaré au niveau du projet Java une ressource Restlet supplémentaire correspondant à la politique de sécurité de Silverlight « clientaccesspolicy.xml ». Pour plus d’informations sur ce sujet, consulter ce billet …

// Defines a route for the client access policy
// so that Services can be accessed from any silverlight application
router.attach("/clientaccesspolicy.xml", ClientAccessPolicyResource.class);


public class ClientAccessPolicyResourceextends Resource {

  public ClientAccessPolicyResource(Context context, Request request,
                    Response response) {
       super(context, request, response);

       // TODO Auto-generated constructor stub
       getVariants().add(new Variant(MediaType.TEXT_XML));
   }

   publicRepresentation represent(Variant variant) {
       StringBuilder builder = new StringBuilder();
       builder.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
       builder.append("<access-policy>");
       builder.append("<cross-domain-access>");
       builder.append("<policy>");
       builder.append("<allow-from http-request-headers=\"*\">");
       builder.append("<domain uri=\"http://localhost:8183\"/>");
       builder.append("</allow-from>");
       builder.append("<grant-to>");
       builder.append("<resource path=\"/customers/\" include-subpaths=\"true\"/>");
       builder.append("</grant-to>");
       builder.append("</policy>");
       builder.append("</cross-domain-access>");
       builder.append("</access-policy>");

       return new StringRepresentation(builder.toString(), variant.getMediaType());
  }  
}

Constitution de l’interface Silverlight

L’application Silverlight que nous vous proposons est orientée informatique de gestion traditionnelle dans le sens où elle implémente le pattern Liste – Détail. Nous avons utilisé les composants proposés par défaut en Silverlight 2. Il serait possible d’enrichir cette application grâce aux composants évolués proposés dans le projet Silverlight Toolkit téléchargeable sur CodePlex ( http://www.codeplex.com/silverlight).

Le projet joint à cet article comprend quatre composants Silverlight :

Composant

Description

App.xaml 

Point d’entrée de l’application Silverlight. Comprend notamment les
ressources / styles.

Home.xaml

Page principale, dans notre cas, il s’agit d’un onglet comprendant 2 section

SearchCustomers.xaml

Chargement d’une liste de clients à partir du filtre positionné.
Affichage du client sélectionné, et possibilité de la modifier ou de la supprimer.

CreateCustomer.xaml

Ecran de création d’un nouveau client

Figure 5 : Description des composants Silverlight

 

Figure 6 : Composants Recherche et Détail

Pour parfaire notre exemple, nous avons intégré la skin « Rough » proposée par Corrina Black sur son blog ( http://blogs.msdn.com/corrinab/archive/2008/08/04/8828013.aspx), et mis à jour pour la version finale de Silverlight 2.

Remarque : Nous intégrons la skin « Rough » dans le code des exemples en téléchargements, dans la mesure où la skin disponible sur le blog de Corrina n’est pas alignée avec la version finale de Silverlight 2. Merci à Corrina qui a pris le temps d’avancer partiellement le portage et a accepté qoue nous vous la transmettions en preview. Néanmoins,  le rendu visuel n’est pas opérationnel ni sous Visual Studio ni dans les Eclipse Tools for Silverlight parce que la Skin Rough  n’arrive pas à être interprétée. Pour accéder au rendu visuel, il est indispensable de supprimer les ressources de Styles. Aussi, nous proposons plusieurs versions du code source de cet article (avec et sans ressources de Style).

 

Exécution des codes accompagnant cet article

Il est possible d’exécuter le code en environnement mixte Java / .Net ou bien pur Java. Pour le détail de ces configurations, nous vous invitons à consulter le billet  « Architecture Series : Pure and Mixed configurations ». Le code accompagnant cet article vous est proposé sous 3 formes :

ConfigurationDescription
1

Mixed Configuration

- 4 XAML components

- No Skin

Il s’agit de la configuration décrite plus haut. La skin Rough n’est pas intégrée afin
que la prévisualiation Visual Studio soit opérationnelle.

Le dossier DataGridRESTClient contient la solution VisualStudio

Le dossier DataGridRESTService contient le projet Eclipse

2

Mixed Configuration

- CustomerDetail component

- Rough Skin

A des fins d’illustration, nous avons capitalisé sur les aspects mise à jour, création
et suppression d’un client au sein d’un composant réutilisé « CustomerDetail.xaml ».

La Skin Rough est intégrée par défaut dans cet exemple.

Le dossier DataGridRESTClient contient la solution VisualStudio

Le dossier DataGridRESTService contient le projet Eclipse

3

Pure Eclipse Configuration

- all XAML inline

- No Skin

Tous les projets peuvent être importés sous Eclipse (voir installation ci-après).

Le code Silverlight a été regroupé dans le fichier Home.xaml. De plus la skin « Rough »
n’est présente.

La pré-visulisation ne fonctionne pas dans la version M2 d’Eclipse4SL.


Exécution d’un environnement Mixte Visual Studio et Eclipse (archives 1 et 2)

Ouvrir la solution DataGridRESTClient dans Visual Studio auquel vous aurez préalablement ajouté les extensions pour Silverlight 2. Cliquer droit sur la page DataGridRESTClientTestPage.html du projet DataGridRESTClient.Web et choisir « View in Browser ».

Importer le projet DataGridRESTService dans votre environnement Eclipse auquel vous aurez préalablement ajouté le framework Restlet en version 1.1.2 ( http://www.restlet.org/downloads/1.1/restlet-1.1.2.exe). Cliquer droit sur CustomerService.java et choisir « Run as … »  puis « Java Application ».

Intégration dans l’environnement Eclipse Tools for Silverlight (archive 3)

Grâce à l’initiative Eclipse Tools for Silverlight (Eclipse4SL), il est possible d’exécuter l’ensemble des codes de l’article sous Eclipse. Néanmoins, dans la mesure où Eclipse4SL ne supporte pas complètement l’intégration de composants, nous vous proposons d’utiliser le code suivant, dans lequel nous avons remplacé le composant CustomerDetail par un code XAML inline.

Importer les trois projets dans votre environnement Eclipse auquel vous aurez préalablement ajouté le framework Restlet en version 1.1.2 ( http://www.restlet.org/downloads/1.1/restlet-1.1.2.exe), et le plugin Eclipse4SL (www.eclipse4SL.org). Cliquer droit sur le projet DataGridRESTClient et choisir « Run as … »  puis « Silverlight Application ».

A propos de l’auteur

Stève Sfartz est architecte en système d’informations chez Microsoft France. Il intervient principalement autour de scénarios d’innovations technologiques et d’interopérabilité  sur les thèmes Cloud Computing, Web 2.0 et SOA. Retrouvez ses billets sur Cloud Computing @ Microsoft France, SOA @ Microsoft France, A Cup of Silverlight, et Think Big mais pas trop …

Cet article a été rédigé avec le concours de Jérôme Louvel et Thierry Boileau de la société Noelios Technologies.

Ressources

-         [RV de l’interop] : RV de l’interopérabilité Silverlight

-         [TechDays 2009] : Tour d’horizon REST

-         [Site Web] : Eclipse Tools for Silverlight

-         [Site Web] : Framework Restlet

-         [Blog] : Silverlight, RIA et Interop

 

Microsoft réalise une enquête en ligne pour comprendre votre opinion sur le site Web de. Si vous choisissez de participer, l’enquête en ligne vous sera présentée lorsque vous quitterez le site Web de.

Souhaitez-vous y participer ?