<?xml version="1.0" encoding="UTF-8"?> <rss
version="2.0"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:wfw="http://wellformedweb.org/CommentAPI/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd"
xmlns:media="http://search.yahoo.com/mrss/"
> <channel><title>Blog Xebia France &#187; SOA</title> <atom:link href="http://blog.xebia.fr/category/soa/feed/" rel="self" type="application/rss+xml" /><link>http://blog.xebia.fr</link> <description>J2EE, Agilité et SOA</description> <lastBuildDate>Wed, 08 Feb 2012 09:23:16 +0000</lastBuildDate> <language>fr</language> <sy:updatePeriod>hourly</sy:updatePeriod> <sy:updateFrequency>1</sy:updateFrequency> <generator>http://wordpress.org/?v=</generator> <copyright>CC BY-NC-ND 2.0 http://creativecommons.org/licenses/by-nc-nd/2.0/fr/</copyright> <managingEditor>blog-france@xebia.com (Xebia France)</managingEditor> <webMaster>blog-france@xebia.com (Xebia France)</webMaster> <ttl>1440</ttl> <image> <url>http://blog.xebia.fr/videos/xebia-podcast.png</url><title>Blog Xebia France</title><link>http://blog.xebia.fr</link> <width>144</width> <height>144</height> </image> <itunes:new-feed-url>http://blog.xebia.fr/feed/podcast/</itunes:new-feed-url> <itunes:subtitle>Les podcasts de Xebia France vous permettent de suivre l&#039;actualité autour de Java, de l&#039;agilité, des technologies Web et bien d&#039;autres. Xebia France est une entreprise spécialisée dans les technologies Java et JEE en environnement agi[...]</itunes:subtitle> <itunes:summary>Les podcasts de Xebia France vous permettent de suivre l&#039;actualité autour de Java, de l&#039;agilité, des technologies Web et bien d&#039;autres. Xebia France est une entreprise spécialisée dans les technologies Java et JEE en environnement agile.</itunes:summary> <itunes:keywords>Xebia, Java, JEE, SOA, Agile, Méthodes, Agiles</itunes:keywords> <itunes:category text="Technology" /> <itunes:category text="Technology"> <itunes:category text="Software How-To" /> </itunes:category> <itunes:category text="Technology"> <itunes:category text="Tech News" /> </itunes:category> <itunes:author>Xebia France</itunes:author> <itunes:owner> <itunes:name>Xebia France</itunes:name> <itunes:email>blog-france@xebia.com</itunes:email> </itunes:owner> <itunes:block>no</itunes:block> <itunes:explicit>no</itunes:explicit> <itunes:image href="http://blog.xebia.fr/videos/xebia-podcast.png" /> <item><title>Kafka</title><link>http://blog.xebia.fr/2011/12/02/kafka/</link> <comments>http://blog.xebia.fr/2011/12/02/kafka/#comments</comments> <pubDate>Fri, 02 Dec 2011 08:00:39 +0000</pubDate> <dc:creator>Guillaume Arnaud</dc:creator> <category><![CDATA[SOA]]></category> <category><![CDATA[Kafka]]></category> <category><![CDATA[MOM]]></category> <guid
isPermaLink="false">http://blog.xebia.fr/?p=9625</guid> <description><![CDATA[Kafka est un Message-Oriented Middleware (MOM) développé par LinkedIn et passé en incubation chez Apache. Ce projet se démarque beaucoup de ses confrères comme les serveurs JMS, AMQP ou autres par des choix d’architecture radicaux que nous allons exposer dans cet article. Écrire pour toujours, consommer vite La structure de persistance de Kafka s’appuie sur [...]]]></description> <content:encoded><![CDATA[<p><a
href="http://incubator.apache.org/kafka/" rel="nofollow">Kafka</a> est un Message-Oriented Middleware (<em>MOM</em>) développé par <a
href="http://www.linkedin.com/" rel="nofollow">LinkedIn</a> et passé en incubation chez Apache. Ce projet se démarque beaucoup de ses confrères comme les serveurs JMS, AMQP ou autres par des choix d’architecture radicaux que nous allons exposer dans cet article.</p><h3><a
name="DRAFT-Kafka-%C3%89crirepourtoujours%2Cconsommervite"></a>Écrire pour toujours, consommer vite</h3><p>La structure de persistance de Kafka s’appuie sur le slogan <em>Don’t fear the filesystem !</em> qui suit la tendance de certaines applications, comme <a
href="https://www.varnish-cache.org/" rel="nofollow">Varnish</a>, fortement contraintes par une stabilité de leurs performances en écriture et par la confiance accordée au disque dur plutôt qu’à la mémoire vive du serveur pour maintenir les données. L’idée vient du constat que l’écriture en RAM peut avoir des comportements difficilement prévisibles dus par exemple au <em>garbage collection</em> sur de grands <em>heap spaces</em> alors que l’écriture en <em>append only</em> sur un fichier peut être très performante tout en assurant un temps constant. L’<a
href="http://varnish.projects.linpro.no/wiki/ArchitectNotes" rel="nofollow">article</a> qui a inspiré Kafka décrit avec plus de détails ces aspects.</p><p>Ce principe se concrétise dans Kafka par l’écriture des messages dans des fichiers de logs, appelés aussi partitions, où chaque ligne contiendra un en-tête assez réduit (essentiellement le checksum) et le message sous forme de string ou encodé avec un serialiseur de son choix (Kafka prend l’exemple d’<a
href="http://avro.apache.org/" rel="nofollow">Avro</a>). La taille de ces fichiers, le nombre de roulements et leur durée de vie sont configurables. Kafka va même plus loin en proposant de configurer la durée et/ou la taille maximale du buffer dans le <em>page cache</em>. Les messages sont donc écrits séquentiellement et  sont gardés pour une durée déterminée par l’utilisateur qui n’a pas de raison de supprimer des messages tant qu’il a de l’espace sur le disque dur. Par contre il n’est pas possible d’écrire au milieu d’un fichier ou de supprimer unitairement un message. Cette règle garantit l’efficacité de l’écriture.</p><p>Ce design apporte un avantage immédiat : il n’y a plus de crainte à avoir lorsqu’on arrête un serveur, il peut récupérer l’ensemble de ses messages au redémarrage. De plus, il a la possibilité de relire la file de messages autant de fois qu’il le veut, il lui suffit de parcourir à nouveau les fichiers de <em>logs,</em> et ce, même plusieurs jours après.</p><p>Les ingénieurs de Kafka sont partis également du postulat que LinkedIn avait surtout besoin de gérer un gros volume de messages, qu’il y aurait toujours au moins un consommateur et qu’il fallait donc privilégier la consommation à la production. Dans l’architecture, cela se concrétise par deux points :</p><ul><li>l’envoi d’un ensemble de messages (<em>MessageSet</em>) plutôt que de messages unitaires, ce qu’on peut faire en JMS avec les regroupements logiques sur la propriété <em>JMSXGroupId</em> du message;</li><li>l’utilisation de l’API Java NIO et plus particulièrement la méthode <a
href="http://docs.oracle.com/javase/6/docs/api/java/nio/channels/FileChannel.html#transferTo(long, long, java.nio.channels.WritableByteChannel)" rel="nofollow"><code>FileChannel.transferTo</code></a> qui permet de sauter l’étape d’écriture dans un buffer côté applicatif et donc d’écrire plus rapidement sur le réseau.</li></ul><h3><a
name="DRAFT-Kafka-Penserdistribu%C3%A9"></a>Penser distribué</h3><p>La gestion des messages sur des serveurs distribués est au cœur de la conception de Kafka. Ce choix est un vrai atout pour la <em>scalabilité</em> de l’application mais complique par ailleurs la compréhension des concepts sous-jacents. Les enjeux étaient de pouvoir augmenter la capacité des serveurs en ajoutant de nouveaux nœuds de façon transparente. Si la quantité de messages augmente, la seule contrainte pour Kafka est d’augmenter l’espace de stockage, ce qui en général ne pose plus de problème dans nos <em>datacenters</em>.</p><p>La distribution est en grande partie assurée grâce à <a
href="http://zookeeper.apache.org/" rel="nofollow">Zookeeper</a>, le service de coordination centralisé d’Apache. Les différents serveurs Kafka communiquent avec Zookeeper pour signaler la topologie du cluster, que ce soit le nombre de partitions qu’ils gèrent ou leur taille.</p><p>De même chaque client s’enregistre dans Zookeeper et peut former des groupes. Un groupe peut être vu comme une queue en JMS, chaque consommateur du même groupe dépilant le même ensemble de messages, ce qui revient à faire du <em>multithreading</em> sur des queues. Si on veut que deux consommateurs lisent indépendamment cet ensemble de messages, comme on aurait plusieurs <em>subscribers</em> sur un même <em>topic</em>, il suffit de créer deux groupes.</p><p>S’il n’est pas évident de calquer notre vision traditionnelle queue/<em>topic</em> sur la conception de Kafka, c’est qu’il n’existe pas de notion de file de messages, mais plutôt de partitions de fichiers distribuées sur plusieurs serveurs. Il est pourtant assez important de comprendre ces concepts sinon on pourrait passer à côté de certains messages !</p><h3><a
name="DRAFT-Kafka-Fairemoinsmaislefairebien"></a>Faire moins mais le faire bien</h3><p>Il existe un certain nombre de fonctionnalités courantes dans les <em>MOM</em> qu’on ne retrouvera pas dans Kafka.  Quelques-unes d’entre elles:</p><ul><li>pas d’acquittement : il n’y a pas de certitude que les clients ont tous consommé chaque message (voir le prochain chapitre);</li><li>pas de sélecteur comme en JMS, un client s’abonne juste à un sujet donné. En effet, on ne retrouve que des informations techniques dans le header du message, comme sa taille ou le CRC. Ce qui fournit peu d’éléments pour filtrer tel ou tel message;</li><li>pas de <em>request</em>/<em>reply </em>: comme le point précédent, le message ne contient pas d’identifiant de corrélation.</li></ul><p>Cette minimisation des fonctionnalités est le prix à payer pour favoriser avant tout le débit des messages. Dans un <em>MOM</em> “classique”, pour s’assurer que tous les consommateurs d’un <em>topic</em> ou d’une queue ont bien récupéré leurs messages suivant les différents scénarios possibles (<em>auto acknowledgement</em>, <em>client acknowledgement</em>, transactions&#8230;), les serveurs auront besoin de maintenir des états complexes. A cela, on peut ajouter la persistance des messages ou la contrainte d’au plus un envoi et on imagine assez bien où les serveurs peuvent perdre du temps.</p><p>Kafka prend les choses beaucoup plus simplement. Le serveur écrit le message sur une de ses partitions et ensuite le consommateur retrouve cette partition pour y lire le message. Par ce design assez simple en apparence, Kafka résout facilement les problématiques d’ordonnancement des messages.</p><h3><a
name="DRAFT-Kafka-Consommerintelligemment"></a>Consommer intelligemment</h3><p>Comme nous l’avons vu précédemment, Kafka ne possède pas de notion d’acquittement. Ce concept est remplacé par celui d’<em>offset</em>. Cet <em>offset</em> représente le <em>high-water mark</em> pour un consommateur, c’est-à-dire l’emplacement du dernier message lu dans le fichier de <em>log</em>. Cet offset est géré par le client lui-même, libre à lui de le déplacer manuellement.</p><p>Encore une fois Kafka transforme une idée simple en un outil puissant. En effet la gestion manuelle de l’offset permet de reparcourir autant de fois qu’on veut une liste de messages. On imagine assez bien l’utilité dans le cas du <em>crash</em> d’un client par exemple, mais on pourrait aussi imaginer qu’un message déclenche un retraitement des <em>n</em> derniers messages pour les envoyer vers une file de messages d’audit.</p><p>Étonnamment, la gestion des transactions côté client devient également assez légère. Par exemple si, à la réception d’un message, le client doit persister des informations dans une base de donnée, à l’intérieur d’une transaction, l’offset peut également être persisté en base dans cette même transaction. Par conséquent, en cas de <em>rollback</em> de la transaction, le client récupérera l’ancien offset et pourra tenter de reconsommer le même message.</p><h3><a
name="DRAFT-Kafka-Alors%2Conselance%3F"></a>Alors, on se lance ?</h3><h4><a
name="DRAFT-Kafka-Estceque%C3%A7as%E2%80%99adresse%C3%A0monprojet%3F"></a>Est-ce que ça s’adresse à mon projet ?</h4><p>Est-ce que Kafka peut répondre à vos besoins ? Pour orienter votre choix, nous voyons déjà trois idées fortes qui sous-tendent cet outil :</p><ul><li>les messages sont de la donnée, ce que Kafka appelle l’<em>activity stream data</em>. Dans un <em>MOM</em> classique le message n’a qu’un état provisoire; une fois consommé et acquitté il a pour vocation de disparaître. Dans Kafka, le message reste, peut être relu et renvoyé. Si on pousse le concept jusqu’au  bout, il n’est plus réellement nécessaire de stocker ces informations ailleurs (dans des archives de logs ou une base de monitoring par exemple), Kafka peut jouer le rôle de _datasource_;</li><li>une donnée doit pouvoir être consommée immédiatement (alerte de sécurité par exemple) et aussi analysée  à froid dans des outils de <em>Business Intelligence</em> sous forme de <em>batch</em>. Avec ce schéma, il n’est plus nécessaire de dupliquer les <em>workflows;</em></li><li>le volume de données ne doit pas être un problème, je dois pouvoir <em>scaler</em> horizontalement en toute transparence.</li></ul><p>Si notre activité contient beaucoup de petites mises à jour, des notifications entre utilisateurs ou des scénarios d’utilisation qu’il est important de savoir rejouer, Kafka est une bonne solution. Il n’est pas étonnant que, outre LinkedIn, les premiers <a
href="https://cwiki.apache.org/confluence/display/KAFKA/Powered+By" rel="nofollow">utilisateurs</a>, <a
href="http://www.tagged.com/" rel="nofollow">Tagged</a> et <a
href="http://www.mate1.com/about" rel="nofollow">Mate1</a>, soient aussi des réseaux sociaux.</p><p>On pourrait aussi imaginer une modélisation pour gérer les flux financiers : d’un côté la mise à jour permanente du cours de la bourse est récupérée par le <em>front office</em>, de l’autre les outils d’analyse de risque, de calcul de <em>PnL</em> (profits et pertes) et d’audit peuvent être déroulés à froid.</p><h4><a
name="DRAFT-Kafka-Lapeintureestelles%C3%A8che%3F"></a>La peinture est-elle sèche ?</h4><p>Lors de nos journées d’échange à Xebia, nous avons pu expérimenter les fonctionnalités de Kafka. La compréhension du <em>workflow</em> a été la difficulté la plus souvent rencontrée. On met du temps à comprendre les concepts et on a la sensation que nos consommateurs relisent les mêmes messages ou au contraire qu’on en perd. La courbe d’apprentissage sera sûrement plus longue que pour utiliser JMS ou AMQP.</p><p>Par ailleurs, l’API java proposée n’est pour l’instant pas très riche même si elle permet déjà de faire l’essentiel. Il y a par exemple des méthodes permettant de reparcourir les partitions mais elles sont d&#8217;assez bas niveau, on aurait aimé des fonctions de recherches plus poussées. Nous n’avons pas testé l’API Scala (Kafka est écrit en Scala !) mais elle semble plus riche de ce point de vue. Néanmoins il ne s’agit que de la version 0.6 et la <a
href="https://issues.apache.org/jira/browse/KAFKA#selectedTab=com.atlassian.jira.plugin.system.project%3Aroadmap-panel" rel="nofollow"><em>roadmap</em></a> de Kafka contient déjà pas mal d’améliorations qui vont dans le bon sens. Par exemple, l’arrivée de la compression et de la réplication devrait contribuer à la maturité de la solution.</p><h3><a
name="DRAFT-Kafka-Conclusion"></a>Conclusion</h3><p>Malgré sa jeunesse, Kafka est sans aucun doute un outil à surveiller. Son passage en projet Apache, s’il passe la phase d’incubation, devrait apporter une meilleure assise en l’ouvrant à de nouveaux cas d’utilisation et en le décloisonnant de l’environnement de LinkedIn. De plus certains projets seront sûrement intéressés par le support d’<a
href="http://hadoop.apache.org/" rel="nofollow">Hadoop</a>, utilisé également pour leurs besoins en interne.</p><p>La complexité de l’architecture peut par contre être un gros frein surtout si le dialogue est difficile avec les équipes opérationnelles. Car même si Zookeeper permet de lier automatiquement les <em>brokers</em> aux consommateurs, il semble préférable que ces derniers connaissent un minimum l’architecture pour certains modes de consommation. De même, pour des questions de performances ou de sécurité, les opérationnels auront peut-être besoin de rapprocher tel serveur à tel producteur ou consommateur de message. Il s’agit d’un vrai défi pour le <em>DevOps</em>.</p><p>Néanmoins Kafka apporte un regard nouveau sur un vieux sujet, les <em>MOM</em>, en proposant des solutions radicalement différentes de ce qu’on trouve ailleurs. Peut-être germera-t-il de nouvelles idées pour de nouvelles solutions de <em>messaging</em> ?</p><div
class="shr-publisher-9625"></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div><div
class='shareaholic-like-buttonset' style='float:none;height:30px;'><a
class='shareaholic-googleplusone' data-shr_size='medium' data-shr_count='true' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2011%2F12%2F02%2Fkafka%2F' data-shr_title='Kafka'></a><a
class='shareaholic-tweetbutton' data-shr_count='horizontal' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2011%2F12%2F02%2Fkafka%2F' data-shr_title='Kafka'></a></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div>]]></content:encoded> <wfw:commentRss>http://blog.xebia.fr/2011/12/02/kafka/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>REST côté client avec JavaScript</title><link>http://blog.xebia.fr/2011/11/14/rest-javascript-client/</link> <comments>http://blog.xebia.fr/2011/11/14/rest-javascript-client/#comments</comments> <pubDate>Mon, 14 Nov 2011 06:00:48 +0000</pubDate> <dc:creator>Yves Amsellem</dc:creator> <category><![CDATA[SOA]]></category> <category><![CDATA[Backbone]]></category> <category><![CDATA[JavaScript]]></category> <category><![CDATA[jQuery]]></category> <category><![CDATA[Require]]></category> <category><![CDATA[REST]]></category> <category><![CDATA[Web-Services]]></category> <guid
isPermaLink="false">http://blog.xebia.fr/?p=9079</guid> <description><![CDATA[Voilà 11 ans que Roy Fielding a introduit REST, le style d&#8217;architecture original du web appliqué aux échanges inter-applications. Reposant sur HTTP, il promet économie, simplicité et profit des structures réseau en place. Voyons comment l&#8217;implémenter via un client JavaScript — présenté ici — communiquant avec un serveur Java — présenté dans un article connexe [...]]]></description> <content:encoded><![CDATA[<p>Voilà 11 ans que Roy Fielding a introduit REST, le style d&#8217;architecture original du web appliqué aux échanges inter-applications. Reposant sur HTTP, il promet économie, simplicité et profit des structures réseau en place. Voyons comment l&#8217;implémenter via un client JavaScript — présenté ici — communiquant avec un serveur Java — présenté dans <a
href=" http://blog.xebia.fr/2011/11/14/rest-java-serveur">un article connexe</a> –. Le code clé-en-main est <a
href="https://github.com/yamsellem/Backbone-Jersey">disponible sur GitHub</a>.</p><p><center><img
src="http://blog.xebia.fr/wp-content/uploads/2011/11/jQueryUI.png" /><img
src="http://blog.xebia.fr/wp-content/uploads/2011/11/plus.png" /><img
src="http://blog.xebia.fr/wp-content/uploads/2011/11/RequireJS.png" /><img
src="http://blog.xebia.fr/wp-content/uploads/2011/11/plus.png" /><img
src="http://blog.xebia.fr/wp-content/uploads/2011/11/backboneJS.jpeg" /></center></p><p>Le client JavaScript que nous allons déployer repose sur <a
href="http://jquery.com/">jQuery</a> — un framework de haute productivité &#8212;, nous lui adjoindrons <a
href="http://documentcloud.github.com/backbone">BackboneJS</a>, un framework MVC REST, et <a
href="http://requirejs.org/docs/api.html">RequireJS</a>, un chargeur de modules à la demande.</p><h3>Ressources et représentations</h3><p>Le serveur auquel se connecte notre client est une boutique en ligne type Amazon. Elle propose une liste de produits, disponibles en quantité limitée, qu&#8217;il est possible de réserver dans un panier client. Deux ressources implémentent ces fonctionnalités :</p><style>table {border: hidden; border-collapse: collapse; font-size: small;}
tr, th, td {border: dotted 1px #6A205F; padding: 5px;}
th {background: #F0EDF1;}</style><table><tr><th> URI</th><th> Verbes disponibles</th><th> Effet</th></tr><tr><td> <code>product</code></td><td> GET, POST</td><td> liste et création de produits</td></tr><tr><td> <code>basket/{username}</code></td><td> GET, DELETE</td><td> panier de <code>username</code>, suppression</td></tr></table><p>Ces ressources produisent et consomment les représentations suivantes :</p><table><tr><td> <a
href="https://github.com/yamsellem/Backbone-Jersey/blob/master/src/main/java/com/xebia/representation/Product.java">product</a></td><td> <code>{id:long, name:string, price:int, links:link[]}</code></td></tr><tr><td> <a
href="https://github.com/yamsellem/Backbone-Jersey/blob/master/src/main/java/com/xebia/representation/Stock.java">stock</a></td><td> <code>{quantity:int, id:long, related:link}</code></td></tr><tr><td> <a
href="https://github.com/yamsellem/Backbone-Jersey/blob/master/src/main/java/com/xebia/representation/Basket.java">basket</a></td><td> <code>{stock:stock, links:link[]}</code></td></tr><tr><td> <a
href="https://github.com/yamsellem/Backbone-Jersey/blob/master/src/main/java/com/xebia/representation/Link.java">link</a></td><td> <code>{href:anyURI, rel:[rels/book,rels/price,rels/payment,rels/related]}</code></td></tr></table><p>Les produits disponibles dans le stock disposeront, via leur attribut links, d&#8217;une relation afin de les ajouter au panier :</p><table><tr><th> Relation</th><th> Ressource</th><th> Effet</th></tr><tr><td> <code>rels/book</code></td><td> <code>/product</code></td><td> réservation d&#8217;une quantité d&#8217;un produit par un client</td></tr></table><p>Se reporter à l&#8217;article connexe pour plus de détails sur les notions de ressource, représentation et relation.</p><h3>Structure du site</h3><p>Notre client web est composé d&#8217;une simple page html, d&#8217;une css et de modules JavaScript. Outre ses headers, la page <a
href="https://github.com/yamsellem/Backbone-Jersey/blob/master/src/main/webapp/index.html">index.html</a> se résume aux lignes suivantes.</p><pre class="brush: xml; title: ; notranslate">
&lt;body&gt;
  &lt;div id=&quot;cart&quot;&gt;&lt;/div&gt;
  &lt;div id=&quot;products&quot;&gt;
    &lt;div id=&quot;product-creation&quot;&gt;&lt;/div&gt;
    &lt;div id=&quot;product-list&quot;&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/body&gt;
</pre><p>Trois emplacements sont prévus dans cette page sous la forme de div ; un pour le panier client, un autre pour ajouter un produit en magasin, un dernier pour lister les produits existants. Vides lors de l&#8217;affichage de la page, ces trois emplacements vont être renseignés par les données serveur via jQuery. Ce dernier permet de manipuler dynamiquement le DOM – le contenu de la page – afin d&#8217;offrir une expérience d&#8217;utilisation sans rafraîchissement.</p><p><a
href="https://github.com/yamsellem/Backbone-Jersey/blob/master/src/main/webapp/css/style.css">La mise en page</a> est simpliste : les produits occupent la majorité de la page, le panier, lui, est confiné dans une « colonne » sur la droite.</p><pre class="brush: xml; title: ; notranslate">
#products {margin-right:250px;}
#cart {float:right; width:250px }
</pre><h3>Modules externes</h3><p>Si jQuery fournit d&#8217;excellents outils pour manipuler le DOM, il est agnostique quant à la structuration du code ; BackboneJS permet de le structurer en MVC et RequireJS de le découper en modules. Commençons par confier la gestion des dépendances à RequireJS dans le head de la page index.html.</p><pre class="brush: xml; title: ; notranslate">
&lt;script
  data-main=&quot;js/main&quot;
  src=&quot;//ajax.cdnjs.com/ajax/libs/require.js/0.24.0/require.min.js&quot;&gt;
&lt;/script&gt;
</pre><p>RequireJS, situé sur un CDN (un repository de librairies), est chargé du code JavaScript de notre page. Pour se faire, il a besoin du point d&#8217;entrée de l&#8217;application, que l&#8217;on nommera <a
href="https://github.com/yamsellem/Backbone-Jersey/blob/master/src/main/webapp/js/main.js">main.js</a>. Dans ce fichier, on récupère la main via une méthode <code>require</code>. Les bibliothèques externes sont importées – le préfixe <code>order!</code> indique qu&#8217;elles seront chargées dans l&#8217;ordre de déclaration – puis notre code exécuté.</p><pre class="brush: jscript; title: ; notranslate">
require({ baseUrl:'/js' },
  [&quot;order!//ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js&quot;,
   &quot;order!//ajax.googleapis.com/ajax/libs/jqueryui/1.8.13/jquery-ui.min.js&quot;,
   &quot;order!//ajax.cdnjs.com/ajax/libs/underscore.js/1.1.6/underscore-min.js&quot;,
   &quot;order!//ajax.cdnjs.com/ajax/libs/backbone.js/0.3.3/backbone-min.js&quot;,
   &quot;order!/lib/jquery.pubsub.min.js&quot;],
  function()
  {
      // application
  }
);
</pre><p>Une fois les librairies externes importées, les classes de l&#8217;application doivent l&#8217;être également. RequireJS permet de moduler une application à loisir, nous retiendrons un découpage « une classe par fichier », de nombreux autres sont imaginables. Il est important de noter que ce découpage est un artifice destiné à faciliter le développement, lors de la mise en production les sources RequireJS seront <a
href="http://requirejs.org/docs/optimization.html">minifiées</a> (compressées et rassemblées au sein d&#8217;un même fichier).</p><pre class="brush: jscript; title: ; notranslate">
require(...,
  function () {
    require([&quot;product/ProductView&quot;,
             &quot;product/ProductCollection&quot;],
    function (ProductView,
              ProductCollection) {
      // application
    });
  }
);
</pre><p>Les classes de l&#8217;application sont déclarées avec leur chemin et manipulées grâce à un alias. Elles doivent être déclarées dans un fichier distinct comme module RequireJS via une méthode <code>define</code> comme nous allons le voir.</p><h3>Créer un produit avec POST</h3><p>Maintenant que la structure du projet est définie, il est temps de connecter le code aux ressources serveur : BackboneJS entre en jeu. Le <a
href="https://github.com/yamsellem/Backbone-Jersey/blob/master/src/main/webapp/template/ProductCreationTemplate.html">formulaire de création de produit</a> est le premier élément à ajouter à la page ; en voici le contenu.</p><pre class="brush: xml; title: ; notranslate">
&lt;form method=&quot;post&quot; onsubmit=&quot;return false&quot; class=&quot;product&quot;&gt;
  &lt;fieldset&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;label&gt;Name: &lt;input type=&quot;text&quot; id=&quot;name&quot; size=&quot;3&quot; /&gt;&lt;/label&gt;&lt;/li&gt;
      &lt;li&gt;&lt;label&gt;Price: &lt;input type=&quot;text&quot; id=&quot;price&quot; size=&quot;3&quot; /&gt;&lt;/label&gt;&lt;/li&gt;
      &lt;li&gt;&lt;label&gt;Stock: &lt;input type=&quot;text&quot; id=&quot;quantity&quot; size=&quot;3&quot; /&gt;&lt;/label&gt;&lt;/li&gt;
    &lt;/ul&gt;
    &lt;input type=&quot;submit&quot; value=&quot;new product&quot; /&gt;
  &lt;/fieldset&gt;
&lt;/form&gt;
</pre><p>Dans un premier temps, la classe <code>ProductCreationView</code> doit écraser l&#8217;emplacement <code>product-creation</code> de index.html avec la template précédente.</p><p>La fichier <a
href="https://github.com/yamsellem/Backbone-Jersey/blob/master/src/main/webapp/js/product/ProductCreationView.js">ProductCreationView</a> est déclaré comme module RequireJS par la méthode <code>define</code> qui le nomme et indique sa dépendance à la template (le préfixe <code>text!</code> permet l&#8217;accès à un fichier plat). Ce module retourne une classe <code>View</code> héritée de BackboneJS qui sera instanciée par l&#8217;appelant.</p><p>Une vue BackboneJS définit :</p><ul><li>l&#8217;élément du DOM qu&#8217;elle manipule (avec jQuery) via la propriété <code>el</code></li><li>son constructeur via la propriété <code>initialize</code></li><li>les évènements capturés sur l&#8217;élément manipulé via la propriété <code>events</code></li></ul><pre class="brush: jscript; title: ; notranslate">
define(&quot;ProductCreationView&quot;,
  ['text!/template/ProductCreationTemplate.html'],
  function(tmpl){
  return Backbone.View.extend({
    el: $('#product-creation'),
    initialize: function(){
      this.el.html(tmpl);
    }
  });
});
</pre><p>Le $ est un alias jQuery. Il donne accès à toutes les méthodes du framework ; avec une chaîne en argument, il joue le rôle de sélecteur. Il identifie un élément du DOM et permet de remplacer son contenu avec <code>el.html(value)</code>. Le #, issu du monde css, représente l&#8217;attribut id d&#8217;une balise html (l&#8217;attribut class est représenté par un point, « . »).</p><p>Lorsqu&#8217;une instance de cette vue est créée, son constructeur écrase l&#8217;élément DOM à l&#8217;id <code>product-creation</code> et le remplace par le contenu de la template.</p><pre class="brush: jscript; title: ; notranslate">
define(&quot;ProductCreationView&quot;,
  function(...){
    events: {
      &quot;click input:submit&quot;: &quot;create&quot;
    },
    create: function() {
      var name = $('#name');
      var price = $('#price');
      var quantity = $('#quantity');
 
      this.collection.create({
        name: name.val(),
        price: price.val()
      });
    }
  });
});
 
define(&quot;ProductCollection&quot;, [], function(){
  return Backbone.Collection.extend({
     url: '/resource/product'
  });
});
</pre><p>Ensuite, lors du clic de l&#8217;utilisateur sur l&#8217;input submit de la template, la méthode <code>create</code> capture la valeur des inputs text <code>Name</code>, <code>Price</code> et <code>Stock</code> et délègue la création du produit à une collection (héritée de la <code>Collection</code> BackeboneJS). Cette dernière déclenche un POST sur la ressource <code>/product</code> avec la représentation qui lui est transmise.</p><p>Le fichier main.js déclare les deux classes <code>ProductCollection</code> et <code>ProductCreationView</code>, les instancie, et communique la collection à la vue afin qu&#8217;elle puisse créer un nouvel élément dans celle-ci (BackboneJS ne dispose pas de contrôleur à hériter). La méthode <code>start</code> est le bootstrap de l&#8217;application RequireJS.</p><pre class="brush: jscript; title: ; notranslate">
require(...,
  function () {
    require([&quot;product/ProductView&quot;,
             &quot;product/ProductCollection&quot;],
    function (ProductView,
              ProductCollection) {
      return {
      start: function() {
        var products = new ProductCollection();
        new ProductCreationView({ collection: products });
      }
    }
  }
);
</pre><p>Récapitulons :</p><ol><li>la page index.html est chargée par le navigateur</li><li>la balise script initialise RequireJS qui donne la main à notre code</li><li>une collection est instanciée avec une référence à la ressource <code>/product</code></li><li>une vue est instanciée avec cette collection</li><li>cette vue charge la template de création de produit dans index.html</li><li>lors d&#8217;une création de produit par l&#8217;utilisateur, la vue appelle <code>create</code> sur la collection de produits</li><li>la collection de produits POST le produit au serveur et récupère celui retourné pour mettre à jour id et links</li></ol><p>L&#8217;échange HTTP obtenu est le suivant :</p><pre class="brush: jscript; title: ; notranslate">
# Request
POST /resource/product HTTP/1.1
Host: localhost:8080
Content-Type: application/json;q=1.0
{
  &quot;name&quot;:&quot;pull&quot;,
  &quot;price&quot;:25
}
 
# Response
HTTP/1.1 201 CREATED
Content-Type: application/json
{
  &quot;id&quot;:0,
  &quot;name&quot;:&quot;pull&quot;,
  &quot;price&quot;:25,
  &quot;links&quot;:[{
    &quot;href&quot;:&quot;resource/product/0/stock/{quantity}/{username}&quot;,
    &quot;rel&quot;:&quot;RELS_BOOK&quot;
  }]
}
</pre><h3>Lister les produits avec GET</h3><p>Maintenant qu&#8217;il est possible d&#8217;ajouter des produits via l&#8217;interface, voyons comment les afficher ; un emplacement est prévu à cet effet, celui à l&#8217;identifiant <code>product-list</code>.</p><pre class="brush: xml; title: ; notranslate">
&lt;form method=&quot;post&quot; onsubmit=&quot;return false&quot;&gt;
  &lt;fieldset&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;strong&gt;&lt;%= product.get('name') %&gt;&lt;/strong&gt;&lt;/li&gt;
      &lt;li&gt;Price: $&lt;%= product.get('price') %&gt;&lt;/li&gt;
      &lt;li&gt;
        &lt;label&gt;
          Qty: &lt;input type=&quot;text&quot; data-id=&quot;&lt;%= product.get('id') %&gt;&quot; value=&quot;1&quot; size=&quot;3&quot;/&gt;
        &lt;/label&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
 
    &lt;input type=&quot;submit&quot; data-id=&quot;&lt;%= product.get('id') %&gt;&quot; value=&quot;add to cart&quot; /&gt;
  &lt;/fieldset&gt;
&lt;/form&gt;
</pre><p>La template précédente permet l&#8217;affichage d&#8217;un produit, elle utilise la syntaxe UnderscoreJS <code><%= value %></code> (utilisé également par BackboneJS ; il existe de nombreux moteurs de templates, <a
href="https://github.com/janl/mustache.js/">MustacheJS</a>, entre autres). Elle est intégrée à la page grâce au code de la classe <a
href="https://github.com/yamsellem/Backbone-Jersey/blob/master/src/main/webapp/js/product/ProductView.js">ProductView</a> qui lui transmet un produit en paramètre. Le produit étant issu d&#8217;une collection BackboneJS, accéder à une propriété passe par un getter.</p><pre class="brush: jscript; title: ; notranslate">
define(&quot;ProductView&quot;,
  ['text!/template/ProductTemplate.html'],
  function(tmpl){
  return Backbone.View.extend({
    el: $(&quot;#product-list&quot;),
    initialize: function(){
      _.bindAll(this, 'render');
      this.collection.bind('add', this.render);
    },
    render: function() {
      var template = '';
      this.collection.each(function(product) {
        template += _.template(tmpl, { product: product });
      });
      this.el.html(template);
    }
  });
});
</pre><p>Le constructeur de cette classe positionne un écouteur sur l&#8217;ajout d&#8217;élément à la collection de produits avec <code>bind</code>. L&#8217;occurrence de cet évènement déclenche la propriété <code>render</code> de la vue. Cette écoute étant effectuée par la collection, le <code>this</code> manipulé par la méthode <code>render</code> de la vue lui est relatif. L&#8217;utilisation d&#8217;une méthode utilitaire d&#8217;Underscore, <code>bindAll</code>, permet de modifier ce comportement en indiquant que le <code>this</code> manipulé par la méthode render est la vue elle-même.</p><p>L&#8217;ajout d&#8217;un produit à la collection manipulée par cette vue ajoute une template pour chaque produit à la page. Les collections BackboneJS offrent une méthode <code>each</code> pour faciliter l&#8217;itération sur leurs éléments. Lorsque plusieurs éléments sont ajoutés à une page, il est plus performant de les concaténer et de les afficher d&#8217;un coup.</p><p>L&#8217;identifiant du produit est positionné sur l&#8217;input submit afin de localiser le produit sélectionné par le client par la suite. L&#8217;input text recevant la quantité réservée le reçoit également à cette fin.</p><h3>Réserver une quantité d&#8217;un produit</h3><p>Afin de permettre la réservation d&#8217;une certaine quantité d&#8217;un article, il est nécessaire d&#8217;ajouter le code suivant à la classe <code>ProductView</code> :</p><pre class="brush: jscript; title: ; notranslate">
define(&quot;ProductView&quot;,
  function(...){
  return Backbone.View.extend({
    events: {
      &quot;click input:submit&quot;: &quot;book&quot;
    },
    book: function(event) {
      var product_id = $(event.target).data('id');
      var quantity = $('input[type=text][data-id=&quot;'+product_id+'&quot;]').val();
 
      var links = this.collection.get(product_id).get('links');
 
      var map = new Object();
      _.each(links, function(link) {
        map[link.rel] = link.href;
      });
 
      $.ajax({
        type: 'POST',
        url: map['RELS_BOOK'].replace('{quantity}', quantity).replace('{username}', &quot;xebia&quot;),
        success: function() {$.publish('basket-event')},
        error: function(xhr) { alert(xhr.responseText) }
      });
    }
  });
});
</pre><p>Le clic sur l&#8217;input submit de la vue est capturé et son évènement déclencheur permet d&#8217;identifier quel produit, parmi la liste proposée, a été sélectionné : <code>event.target</code> permet d&#8217;accéder à l&#8217;input submit qui a reçu le clic. Il est alors possible de récupérer ses attributs, ici son <code>data-id</code> (cet identifiant est préférable à <code>id</code> car il est utilisé pour deux éléments, la quantité et le bouton submit). Les collections BackboneJS offrent une méthode <code>get(id)</code> permettant d&#8217;accéder à un élément par son identifiant. La quantité est récupérée à l&#8217;aide d&#8217;un sélecteur jQuery.</p><p>Les relations proposées par le produit sélectionné sont copiées dans une map, et la template de réservation d&#8217;un produit est complétée (<code>quantity</code> et <code>username</code>). Un POST est réalisé sur le lien obtenu.</p><h3>Afficher le panier</h3><p>Lors du succès d&#8217;une réservation, le panier doit être rafraîchi. La ressource <code>/product</code> ajoute un ou plusieurs produits dans le panier utilisateur, représenté par la ressource <code>/basket</code>. La ressource <code>/basket</code> ne remonte donc aucune notification au client, puisqu&#8217;elle est modifiée côté serveur. Il donc nécessaire, comme le fait le handler <code>success</code> de l&#8217;appel de réservation, de publier un évènement lors du succès d&#8217;un achat à destination du panier afin qu&#8217;il se rafraîchisse. Cette gestion d&#8217;évènements est ajoutée à jQuery par <a
href="https://gist.github.com/661855">Tiny Pub/Sub</a>.</p><pre class="brush: jscript; title: ; notranslate">
define(&quot;BasketView&quot;,
  function(...) {
  return Backbone.View.extend({
    el: $('#cart'),
 
    var view = this;
    $.subscribe('basket-event', view.fetch);
  },
  fetch: function() {
    var view = this;
    this.model.clear();
    this.model.fetch({ success: view.render });
  },
  price:0,
  render: function() {
    var stocks = this.model.get('stock');
    var view = this;
    var tmpl = '';
    var total = 0;
 
    _.each(stocks, function(stock) {
        var product = view.collection.get(stock.id);
        var price = stock.quantity * product.get('price');
        total += price;
        tmpl += _.template(basketItemTemplate,
                          { quantity: stock.quantity,
                            name: product.get('name'),
                            price: price });
    });
    this.el.html(_.template(basketTemplate, { total: total }));
    $('tbody', this.el).html(tmpl);
    this.price = total;
  });
});
</pre><p>Deux templates sont nécessaires à l&#8217;affichage du panier : un tableau et un élément répété pour chaque produit. Le calcul du prix du panier est effectué côté client ; lors d&#8217;un clic utilisateur sur le bouton « checkout » le prix est comparé à celui retourné par le serveur et, s&#8217;il est correct, le payement est effectué et le panier vidé (la comparaison du prix et son calcul côté client sont, bien entendu, réalisés à des fins didactiques).</p><pre class="brush: jscript; title: ; notranslate">
define(&quot;BasketView&quot;,
  function(...) {
  return Backbone.View.extend({
    events: {
      &quot;click input:submit&quot;: &quot;checkout&quot;
    },
    checkout: function() {
      var links = this.model.get('links');
      var map = {};
 
      _.each(links, function(link) {
        map[link.rel] = link.href;
      });
 
      var total = this.price;
      $.getJSON(map['RELS_PRICE'], function(response) {
        if(response.value == total)
          $.post(map['RELS_PAYMENT'], function() { $.publish('basket-event') });
      });
    }
  });
});
</pre><h3>Épilogue</h3><p>L&#8217;interface unifiée de HTTP offerte par BackboneJS simplifie grandement l&#8217;interaction avec un serveur REST (en plus des exemples présentés ici, la modification d&#8217;un élément déclenche un PUT, sa suppression un DELETE). L&#8217;utilisation d&#8217;une liste de relations, plutôt que d&#8217;URI, entre client et serveur diminue encore leur couplage. Pour approfondir le sujet davantage, se référer à l&#8217;article de référence sur <a
href="http://addyosmani.com/blog/large-scale-jquery">l&#8217;intégration des solutions jQuery dans l&#8217;entreprise</a>.</p><div
class="shr-publisher-9079"></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div><div
class='shareaholic-like-buttonset' style='float:none;height:30px;'><a
class='shareaholic-googleplusone' data-shr_size='medium' data-shr_count='true' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2011%2F11%2F14%2Frest-javascript-client%2F' data-shr_title='REST+c%C3%B4t%C3%A9+client+avec+JavaScript'></a><a
class='shareaholic-tweetbutton' data-shr_count='horizontal' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2011%2F11%2F14%2Frest-javascript-client%2F' data-shr_title='REST+c%C3%B4t%C3%A9+client+avec+JavaScript'></a></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div>]]></content:encoded> <wfw:commentRss>http://blog.xebia.fr/2011/11/14/rest-javascript-client/feed/</wfw:commentRss> <slash:comments>2</slash:comments> </item> <item><title>REST côté serveur avec Java</title><link>http://blog.xebia.fr/2011/11/14/rest-java-serveur/</link> <comments>http://blog.xebia.fr/2011/11/14/rest-java-serveur/#comments</comments> <pubDate>Mon, 14 Nov 2011 06:00:09 +0000</pubDate> <dc:creator>Yves Amsellem</dc:creator> <category><![CDATA[SOA]]></category> <category><![CDATA[Java / JEE]]></category> <category><![CDATA[Jersey]]></category> <category><![CDATA[REST]]></category> <category><![CDATA[Web-Services]]></category> <guid
isPermaLink="false">http://blog.xebia.fr/?p=9033</guid> <description><![CDATA[Voilà 11 ans que Roy Fielding a introduit REST, le style d&#8217;architecture original du web appliqué aux échanges inter-applications. Reposant sur HTTP, il promet économie, simplicité et profit des structures réseau en place. Voyons comment l&#8217;implémenter via un client JavaScript — présenté dans un article connexe — communiquant avec un serveur Java — présenté ici [...]]]></description> <content:encoded><![CDATA[<p>Voilà 11 ans que Roy Fielding a introduit REST, le style d&#8217;architecture original du web appliqué aux échanges inter-applications. Reposant sur HTTP, il promet économie, simplicité et profit des structures réseau en place. Voyons comment l&#8217;implémenter via un client JavaScript — présenté dans <a
href="http://blog.xebia.fr/2011/11/14/rest-javascript-client">un article connexe</a> — communiquant avec un serveur Java — présenté ici –. Le code clé-en-main est <a
href="https://github.com/yamsellem/Backbone-Jersey">disponible sur GitHub</a>.</p><div
style="border: dotted 1px #6A205F; background: #F0EDF1; padding:10px 30px;"><p><a
href="http://java.net/projects/jsr311">JAX-RS</a> — Java API for RESTful Web Services — standardise l&#8217;implémentation de REST en Java (une API + une servlet). Nous retiendrons son implémentation de référence, <a
href="http://jersey.java.net/nonav/documentation/latest/user-guide.html">Jersey</a>, et la déploierons sur un serveur <a
href="http://docs.codehaus.org/display/JETTY/Embedding+Jetty">Jetty-Embedded</a> (le code clé-en-main dispose d&#8217;un <code>main</code> effectuant le déploiement ; pas besoin d&#8217;installer de serveur).</p><p>Les web services REST sont des ressources. Une ressource est identifiée par un nom du domaine, produit, commande, etc. HTTP définit 7 verbes pour manipuler les ressources :</p><ul><li><string>GET pour la lecture,</li><li>PUT pour la modification,</li><li>DELETE pour la suppression,</li><li>POST pour la création et autre,</li><li>OPTIONS (verbes disponibles), HEAD (prise de pouls) et TRACE (écho des headers de l&#8217;appelant) non abordés</li></ul></div><p>Une fois déployée, la servlet Jersey mappe l&#8217;url <code>/resource/*</code> ; la partie cliente est disponible sur <code>/index.html</code>. Le web.xml définit deux filtres Jersey afin de loguer les trames HTTP des échanges client-serveur.</p><p>Par convention, GET <code>/product</code> liste tous les produits, GET <code>/product/12</code> affiche le produit identifié, PUT <code>/product/12</code> remplace le produit identifié par celui transmit, DELETE <code>/product/12</code> supprime le produit identifié, POST <code>/product</code> crée le produit transmis et fourni son identifiant en réponse. Les verbes GET, PUT et DELETE sont sûrs et idempotents (sans effet de bord – effet identique à requête identique). POST est utilisé comme factory (ici pour créer de nouveaux produits) et pour toute opération non sûre ou non idempotente (par exemple, déplacer une quantité du stock vers un panier). Les navigateurs internet utilisent abondamment GET pour accéder au contenu d&#8217;une page web et POST lors de la soumission d&#8217;un formulaire.</p><h3><a
name="Ressources"></a>Ressources</h3><p>L&#8217;application que nous nous apprêtons à développer est une boutique en ligne type Amazon. Elle propose une liste de produits, disponibles en quantité limitée, qu&#8217;il est possible de réserver dans un panier client. Deux ressources implémentent ces fonctionnalités, <a
href="https://github.com/yamsellem/Backbone-Jersey/blob/master/src/main/java/com/xebia/resource/ProductResource.java">ProductResource</a> et <a
href="https://github.com/yamsellem/Backbone-Jersey/blob/master/src/main/java/com/xebia/resource/BasketResource.java">BasketResource</a>, dont voici les définitions :</p><style>table {border: hidden; border-collapse: collapse; font-size: small;}
tr, th, td {border: dotted 1px #6A205F; padding: 5px;}
th {background: #F0EDF1;}</style><table><tr><th> URI</th><th> Verbes disponibles</th><th> Effet</th></tr><tr><td> <code>product</code></td><td> GET, POST</td><td> liste et création de produits</td></tr><tr><td> <code>product/{id}</code></td><td> GET, DELETE</td><td> produit accessible, supprimable par <code>id</code></td></tr><tr><td> <code>product/{id}/stock</code></td><td> GET, POST</td><td> stock d&#8217;un produit, ajout de quantité</td></tr><tr><td> <code>product/{id}/stock/{quantity}/{username}</code></td><td> POST</td><td> réservation client</td></tr><tr><td> <code>basket/{username}</code></td><td> GET, DELETE</td><td> panier de <code>username</code>, suppression</td></tr><tr><td> <code>basket/{username}/{productid}</code></td><td> GET</td><td> stock d&#8217;un produit</td></tr><tr><td> <code>basket/{username}/price</code></td><td> GET</td><td> prix du panier</td></tr><tr><td> <code>basket/{username}/payment</code></td><td> POST</td><td> paiement du panier</td></tr></table><p>Récupérer la liste des produits s&#8217;effectue avec un GET sur http://localhost:8080/resource/product.</p><p>À l&#8217;instar de la navigation sur internet, naviguer entre ressources s&#8217;effectue à l&#8217;aide de liens. Alors que sur le web c&#8217;est le nom du lien qui aiguille l&#8217;internaute, ici c&#8217;est la relation — l&#8217;attribut rel — qui permet de naviguer. HTTP définit <a
href="http://dev.w3.org/html5/spec/Overview.html#linkTypes">des relations standards</a>, pour couvrir les besoins de l&#8217;exercice, les suivantes lui sont ajoutées et communiquées au client :</p><table><tr><th> Relation</th><th> Ressource</th><th> Effet</th></tr><tr><td> <code>rels/book</code></td><td> <code>/product</code></td><td> réservation d&#8217;une quantité d&#8217;un produit par un client</td></tr><tr><td> <code>rels/price</code></td><td> <code>/basket</code></td><td> accès au prix du panier</td></tr><tr><td> <code>rels/payment</code></td><td> <code>/basket</code></td><td> accès au paiement du panier</td></tr><tr><td> <code>rels/related</code></td><td> <code>*</code></td><td> standard, utilisé ici pour donner accès à un produit du panier client</td></tr></table><h3><a
name="Representations"></a>Représentations</h3><p>Les représentations sont les objets échangés entre client et serveur (en XML ou JSON, à la demande du client). Elles sont <a
href="https://github.com/yamsellem/Backbone-Jersey/blob/master/src/main/resources/representation.xsd">définies dans un XSD</a>. Côté serveur, la grappe d&#8217;objets équivalente est générée par XJC. <a
href="http://blog.xebia.fr/2011/03/17/jaxb-le-parsing-xml-objet">Un précédent article</a> aborde les notions de JAXB en détails. Voici une définition compacte des représentations :</p><table><tr><td> <a
href="https://github.com/yamsellem/Backbone-Jersey/blob/master/src/main/java/com/xebia/representation/Product.java">product</a></td><td> <code>{id:long, name:string, price:int, links:link[]}</code></td></tr><tr><td> <a
href="https://github.com/yamsellem/Backbone-Jersey/blob/master/src/main/java/com/xebia/representation/Stock.java">stock</a></td><td> <code>{quantity:int, id:long, related:link}</code></td></tr><tr><td> <a
href="https://github.com/yamsellem/Backbone-Jersey/blob/master/src/main/java/com/xebia/representation/Basket.java">basket</a></td><td> <code>{stock:stock, links:link[]}</code></td></tr><tr><td> <a
href="https://github.com/yamsellem/Backbone-Jersey/blob/master/src/main/java/com/xebia/representation/Price.java">price</a></td><td> <code>{value:int}</code></td></tr><tr><td> <a
href="https://github.com/yamsellem/Backbone-Jersey/blob/master/src/main/java/com/xebia/representation/Link.java">link</a></td><td> <code>{href:anyURI, rel:[rels/book,rels/price,rels/payment,rels/related]}</code></td></tr></table><p>La servlet Jersey est initialisée avec le paramètre <a
href="http://jersey.java.net/nonav/documentation/latest/json.html">POJOMappingFeature</a> afin d&#8217;utiliser <a
href="http://wiki.fasterxml.com/JacksonDocumentation">Jackson</a> pour le marshalling JSON plutôt que <a
href="http://jaxb.java.net/tutorial">JAXB</a>, dont la responsabilité est ici limitée au marshalling XML. Jackson produit un JSON plus standard — la dépendance jersey-json est ajoutée au <a
href="https://github.com/yamsellem/Backbone-Jersey/blob/master/pom.xml">pom.xml</a>.</p><p>JAXB requiert l&#8217;annotation <a
href="http://download.oracle.com/javase/6/docs/api/javax/xml/bind/annotation/XmlRootElement.html">@XmlRootElement</a> afin de produire/consommer les objets du modèle en XML. Jackson n&#8217;en nécessite aucune.</p><p>Les représentations et les ressources sont intimement liées. Leur nommage gagne à être cohérent : la ressource <code>/product</code> produit une List<Product> lors d&#8217;un GET et consomme un Product lors d&#8217;un POST ; la ressource <code>/stock</code> produit et consomme un Stock. Sans information (le déplacement d&#8217;un produit dans le panier et le paiement), aucune représentation n&#8217;est consommée ni produite, seuls l&#8217;URI, le statut de retour et les headers caractérisent l&#8217;échange.</p><h3><a
name="Status"></a>Status de retour</h3><p>Quelle que soit l&#8217;opération demandée, les ressource indiquent toujours un statut de retour. Ce code, composé de 3 chiffres dont le premier spécifie la catégorie (1. information, 2. succès, 3. redirection, 4. erreur client, 5. erreur serveur), est indiqué à chaque appel de ressource, quel que soit le verbe HTTP utilisé et la présence, ou non, de représentation. 200, 301 et 404 sont les plus connus, ils indiquent, dans l&#8217;ordre, un succès, une redirection et l&#8217;absence du document recherché. Se référer à <a
href="http://fr.wikipedia.org/wiki/Liste_des_codes_HTTP">la liste des statuts HTTP</a> pour plus de détail.</p><h3><a
name="Headers"></a>Headers</h3><p>Une trame HTTP est composée, en plus d&#8217;une représentation — le body — et d&#8217;un statut de retour, de headers — l&#8217;entête –. <a
href="http://en.wikipedia.org/wiki/List_of_HTTP_header_fields">Les headers HTTP</a>, une liste de propriétés clé/valeur, en plus de véhiculer la négociation de médiatype, communiquent des informations <a
href="http://fr.wikipedia.org/wiki/Cache-Control">de cache</a>, <a
href="http://en.wikipedia.org/wiki/HTTP_ETag">de concurrence</a> et <a
href="http://fr.wikipedia.org/wiki/HTTP_Authentification">de sécurité</a> notamment. <a
href="http://blog.xebia.fr/2011/04/18/apache-shiro">Un précédent article</a> aborde les notions d&#8217;authentification HTTP en détails.</p><h3><a
name="Produits"></a>Ressource produit</h3><p>L&#8217;intégralité du code étant <a
href="https://github.com/yamsellem/Backbone-Jersey">disponible sur GitHub</a>, nous nous focaliserons sur les points clé de l&#8217;implémentation. Toute latitude est laissée au lecteur d&#8217;aller et venir entre les explications suivantes et le code lié. Afin de simplifier la compréhension, le rôle du référentiel de données est joué par des classes dotées de méthodes statiques, <a
href="https://github.com/yamsellem/Backbone-Jersey/blob/master/src/main/java/com/xebia/data/Products.java">Products</a>, <a
href="https://github.com/yamsellem/Backbone-Jersey/blob/master/src/main/java/com/xebia/data/Stocks.java">Stocks</a> et <a
href="https://github.com/yamsellem/Backbone-Jersey/blob/master/src/main/java/com/xebia/data/Purchases.java">Purchases</a>. Commençons avec la classe <a
href="https://github.com/yamsellem/Backbone-Jersey/blob/master/src/main/java/com/xebia/resource/ProductResource.java">ProductResource</a>.</p><pre class="brush: java; title: ; notranslate">
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;
 
@Path(&quot;/product&quot;)
public class ProductResource {
    @GET
    @Path(&quot;/{id}&quot;)
    public Response get(@PathParam(&quot;id&quot;) long id) {
        Product product = Products.get(id);
        return Response.ok(product).build();
    }
 
    @POST
    public Response post(Product product) {
        Products.put(product);
        return Response.ok(product).build();
    }
 
    @GET
    public Response get() {
        List&lt;Product&gt; products = Products.get();
        GenericEntity&lt;List&lt;Product&gt;&gt; entity = new GenericEntity&lt;List&lt;Product&gt;&gt;(products) {};
        return Response.ok(entity).build();
    }
}
</pre><p>L&#8217;annotation <a
href="http://jersey.java.net/nonav/documentation/latest/jax-rs.html#d4e110">@Path</a> permet de déclarer l&#8217;URI d&#8217;une ressource au niveau d&#8217;une classe puis de la compléter si nécessaire au niveau méthode (le scannage de Jersey peut être restreint à un package dans le web.xml). Les méthodes HTTP sont représentées quant à elles par des annotations du même nom @GET, @PUT, @DELETE et @POST appartenant au package <a
href="http://download.oracle.com/javaee/6/api/javax/ws/rs/package-summary.html">javax.ws.rs</a> de JAX-RS. Du même package, le builder Response permet notamment de positionner le code de retour (la méthode <code>ok(...)</code> le positionne à 200), la représentation retournée, les headers, etc.</p><p><a
href="http://jersey.java.net/nonav/apidocs/latest/jersey/javax/ws/rs/core/GenericEntity.html">GenericEntity</a> est nécessaire lors de la production d&#8217;une List<Product> en guise de réponse. Les implémentations de List n&#8217;étant pas annotés avec JAXB, cette encapsulation permet de positionner une liste au premier nœud du graphe.</p><p>En cas d&#8217;absence du produit, une NotFoundException est levée par <a
href="https://github.com/yamsellem/Backbone-Jersey/blob/master/src/main/java/com/xebia/data/Products.java">Products</a>. Cette exception, de la famille des WebApplicationException est capturée par un <a
href="https://github.com/yamsellem/Backbone-Jersey/blob/master/src/main/java/com/xebia/resource/WebApplicationExceptionMapper.java">mapper</a> annoté <a
href="http://jersey.java.net/nonav/documentation/latest/user-guide.html#d4e443">@Provider</a>. Cette classe d&#8217;exceptions introduite par Jersey remonte une réponse avec statut de retour approprié : ici, 404.</p><p>La classe <a
href="https://github.com/yamsellem/Backbone-Jersey/blob/master/src/main/java/com/xebia/representation/Product.java">Product</a> (générée par XJC) est la représentation consommée et produite par cette ressource ; elle a été réduite ici à sa plus simple expression.</p><pre class="brush: java; title: ; notranslate">
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
 
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Product {
    protected long id;
    protected String name;
    protected int price;
    protected List&lt;Link&gt; links;
}
</pre><p>Lors d&#8217;un appel à cette ressource le header Accept permet d&#8217;indiquer les préférences du médiatype utilisé pour communiquer la représentation. Le navigateur Chrome, par exemple, indique les suivants Accept: <code>text/html,application/xml;q=0.9,/;q=0.8</code>. Ceux-ci sont pondérés, ainsi il préfère XML (0.9) à JSON (0.8, */* indiquant ceux non exprimés auparavant). Il obtient donc la représentation en XML :</p><pre class="brush: xml; title: ; notranslate">
&lt;products&gt;
  &lt;product&gt;
    &lt;id&gt;0&lt;/id&gt;
    &lt;name&gt;pull&lt;/name&gt;
    &lt;price&gt;25&lt;/price&gt;
    &lt;links&gt;
      &lt;href&gt;resource/product/0/stock/{quantity}/{username}&lt;/href&gt;
      &lt;rel&gt;rels/book&lt;/rel&gt;
    &lt;/links&gt;
  &lt;/product&gt;
&lt;/products&gt;
</pre><p>Appelé d&#8217;un client JavaScript la représentation sera bien plus compacte, grâce au JSON :</p><pre class="brush: jscript; title: ; notranslate">
[{
  &quot;id&quot;: 0,
  &quot;name&quot;: &quot;pull&quot;,
  &quot;price&quot;: 25,
  &quot;links&quot;: [{
    &quot;href&quot;: &quot;resource/product/0/stock/{quantity}/{username}&quot;,
    &quot;rel&quot;: &quot;RELS_BOOK&quot;}]
}]
</pre><p>Ces représentations ont été indentées, sans quoi, elles seraient exprimées sur une simple ligne.</p><p>L&#8217;échange client serveur peut être simplifié ainsi :</p><pre class="brush: jscript; title: ; notranslate">
# Request
GET /product HTTP/1.1
Host: localhost:8080
Accept: application/json;q=1.0
 
# Response
HTTP/1.1 200 OK
Content-Type: application/json
[{&quot;id&quot;: 0...}]
</pre><h3><a
name="TestsProduits"></a>Tests produit</h3><p>Afin de s&#8217;assurer du fonctionnement de cette première ressource, un serveur Jetty-Embedded peut être déployé et une batterie de tests exécutée à l&#8217;aide du client Jersey. Voyons comment avec la classe <a
href="https://github.com/yamsellem/Backbone-Jersey/blob/master/src/test/java/com/xebia/resource/ProductResourceTest.java">ProductResourceTest</a> et son référentiel de données <a
href="https://github.com/yamsellem/Backbone-Jersey/blob/master/src/test/java/com/xebia/resource/Shipments.java">Shipments</a>.</p><pre class="brush: java; title: ; notranslate">
import static com.sun.jersey.api.client.ClientResponse.Status.OK;
import static com.sun.jersey.api.client.ClientResponse.Status.NOT_FOUND;
 
import org.junit.Rule;
import javax.ws.rs.core.UriBuilder;
 
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
 
public class ProductResourceTest {
  @Rule
  public EmbeddedTestServer server = new EmbeddedTestServer();
 
  @Before
  public void before() {
    for (Product product : Shipments.products())
      productResource().post(product);
  }
 
  @Test
  public void shouldGetProduct() {
    Product product = productResource(2).get(Product.class);
    assertNotNull(product);
    assertEquals(product.getName(), &quot;L'étranger&quot;);
  }
 
  @Test
  public void shouldNotGetUnexistingProduct() {
    ClientResponse response = productResource(12).get(ClientResponse.class);
    assertEquals(response.getStatus(), NOT_FOUND.getStatusCode());
  }
 
  @Test
  public void shouldListProducts() {
    ClientResponse clientResponse = productResource().get(ClientResponse.class);
    List&lt;Product&gt; products = clientResponse.getEntity(new GenericType&lt;List&lt;Product&gt;&gt;() {});
 
    assertEquals(OK.getStatusCode(), clientResponse.getStatus());
    assertEquals(Shipments.size(), products.size());
  }
 
  /* helpers */
 
  private WebResource productResource() {
    URI uri = UriBuilder.fromPath(&quot;resource/product&quot;).build();
    return Client.create().resource(server.uri()).path(uri.getPath());
  }
 
  private WebResource productResource(long productId) {
    URI uri = UriBuilder.fromPath(&quot;resource/product/{id}&quot;).build(productId);
    return Client.create().resource(server.uri()).path(uri.getPath());
  }
}
</pre><p>L&#8217;annotation <a
href="http://www.junit.org/node/580">@Rule</a> permet d&#8217;externaliser <a
href="https://github.com/yamsellem/Backbone-Jersey/blob/master/src/test/java/com/xebia/rule/EmbeddedTestServer.java">le lancement du serveur</a> (basé sur le <a
href="https://github.com/yamsellem/Backbone-Jersey/blob/master/src/main/webapp/WEB-INF/web.xml">web.xml</a>). L&#8217;initialisation réalisée par l&#8217;annotation @Before utilise POST comme une factory pour créer, un à un, de nouveaux produits. Les tests utilisent GET pour vérifier la présence de ceux-ci (et leur numérotation côté serveur). Les listes nécessitent l&#8217;utilisation de <a
href="http://jersey.java.net/nonav/apidocs/latest/jersey/com/sun/jersey/api/client/GenericType.html">GenericType</a> afin de conserver leur typage.</p><p>Le client a généré, au préalable, les représentations avec XJC. Ainsi, il peut demander l&#8217;unmarshalling de la réponse à Jersey. On notera l&#8217;accès direct à la classe Product dans le premier test et le passage préalable par ClientResponse dans le second, donnant accès, en plus de la représentation de la réponse, à son statut et ses headers. On notera également la gestion de template proposée par <a
href="http://jackson.codehaus.org/javadoc/jax-rs/1.0/javax/ws/rs/core/UriBuilder.html">UriBuilder</a> dont la méthode <code>build(...)</code> remplace les différents tags.</p><h3><a
name="Stocks"></a>Ressource stock</h3><p>La notion de stock d&#8217;un produit lui est indépendante. Positionner le stock comme attribut de produit porte à confusion : déplacer un produit du stock vers le panier client ne doit pas concerner tout le stock, seulement la quantité réservée. Pour autant, définir une ressource indépendante /stock/{productid} est ambiguë. Une manière plus élégante est de l&#8217;exprimer comme noeud du produit <code>/product/{id}/stock</code> ; cela traduit bien l&#8217;appartenance de l&#8217;un à l&#8217;autre sans impliquer la présence d&#8217;un attribut dans la représentation. Les / d&#8217;une URL définissent toujours une hiérarchie.</p><p>L&#8217;implémentation suivante considère l&#8217;ajout au stock comme un arrivage et utilise donc POST. Si l&#8217;accès au stock avait été considéré comme le remplacement de la quantité existante, PUT aurait été retenu.</p><pre class="brush: java; title: ; notranslate">
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.EntityTag;
import com.google.common.base.Objects;
 
@Path(&quot;/product&quot;)
public class ProductResource {
  @POST
  @Path(&quot;/{id}/stock&quot;)
  public Response addToStock(@PathParam(&quot;id&quot;) long id, Stock stock) {
    Integer instock = Stocks.quantity(id);
    Stocks.put(id, instock + stock.getQuantity());
    return Response.status(Status.ACCEPTED).build();
  }
 
  @GET
  @Path(&quot;/{id}/stock&quot;)
  public Response stock(@PathParam(&quot;id&quot;) long id) {
    Stock stock = new Stock();
    stock.setQuantity(Stocks.quantity(id));
    return Response.ok(stock).tag(eTag(id, stock.getQuantity())).build();
  }
 
  private EntityTag eTag(long id, int quantity) {
    return new EntityTag(String.valueOf(Objects.hashCode(id, quantity)));
  }
}
</pre><p>L&#8217;ajout de stock vérifie au préalable l&#8217;existence du produit et renseigne le statut de la réponse en conséquence (Stocks s&#8217;en remet à Products qui lève une NotFoundException le cas échéant). La classe-représentation consommée et produite par cette ressource est la suivante.</p><pre class="brush: java; title: ; notranslate">
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Stock {
  protected int quantity;
  protected long id;
  protected Link related;
}
</pre><p>Lors de l&#8217;accès à la ressource stock un tag d&#8217;accès concurrent est ajouté aux headers. Ce dernier est calculé à partir du hash de l&#8217;id produit et de la quantité disponible. Lorsqu&#8217;il veut réserver une certaine quantité du stock, le client fournit ce tag — qu&#8217;il estime être le dernier en date — afin que le serveur puisse lui indiquer si la ressource a changé depuis (ici, si la quantité a changé). Si c&#8217;est le cas, le client doit la récupérer à nouveau du serveur. Lorsque les deux tags correspondent, le serveur accepte la demande client.</p><p>Ce tag peut également permettre 1. de ne pas reconstruire une grappe d&#8217;objets côté serveur si le client a déjà sa dernière version 2. de gérer la concurrence de modification d&#8217;une ressource.</p><pre class="brush: java; title: ; notranslate">
import javax.ws.rs.core.Request;
import javax.ws.rs.core.Context;
 
@Path(&quot;/product&quot;)
public class ProductResource {
  @POST
  @Path(&quot;/{id}/stock/{quantity}/{username}&quot;)
  public Response post(@PathParam(&quot;id&quot;) long id, @PathParam(&quot;quantity&quot;) int quantity,
      @PathParam(&quot;username&quot;) String username, @Context Request request) {
 
    String message;
    int productQuantity = Stocks.quantity(id);
 
    if (request.evaluatePreconditions(eTag(id, productQuantity)) == null) {
      if (Stocks.sell(id, quantity)) {
        Purchases.put(username, id, quantity);
        return Response.ok().build();
 
      } else message = &quot;Product is out of stock&quot;;
    } else message = &quot;eTag mismatch&quot;;
    return Response.status(Status.PRECONDITION_FAILED).entity(message).build();
  }
}
</pre><p>Lors de la réservation d&#8217;un produit, le tag transmis est comparé (par le biais d&#8217;une méthode utilitaire de Request) à sa valeur actuelle. Si ce calcul est couteux, la valeur du hash peut être sauvegardée avec l&#8217;objet afin d&#8217;économiser ce coût. Cette comparaison renvoie un statut 412 si un problème se produit. Ensuite, le stock est décrémenté s&#8217;il lui reste assez d&#8217;articles (la méthode sell renvoie un booléen acquittant l&#8217;opération).</p><p>Lorsqu&#8217;une erreur se produit, la réponse, en plus du code 412 — préconditions non respectées –, se voit dotée d&#8217;un message d&#8217;erreur approprié.</p><p>Afin de limiter le couplage, le lien de réservation ne sera pas connu par le client. Ce dernier sera averti de l&#8217;accès à la réservation par la présence d&#8217;une relation <code>rels/book</code>. Cette relation est ajoutée au produit lors de sa création via POST.</p><pre class="brush: java; title: ; notranslate">
@Path(&quot;/product&quot;)
public class ProductResource {
  @POST
  public Response post(Product product) {
    Products.put(product);
    addBookLink(product);
    return Response.ok(product).build();
  }
 
  static UriBuilder uriBuilder = //
  UriBuilder.fromPath(&quot;resource/product&quot;).path(&quot;{id}/stock/{quantity}/{username}&quot;);
 
  private void addBookLink(Product product) {
    Link link = new Link();
    URI uri = uriBuilder.build(product.getId(), &quot;{quantity}&quot;, &quot;{username}&quot;);
    link.setHref(uri.getPath());
    link.setRel(Rels.RELS_BOOK);
    product.getLinks().add(link);
  }
}
</pre><p>Enfin, une fois une quantité du stock déplacée vers un panier client, une ressource va permettre l&#8217;accès au panier d&#8217;un client. N&#8217;ayant que peu de sens sans le nom du client, ce paramètre est rendu général à la classe.</p><pre class="brush: java; title: ; notranslate">
@Path(&quot;/basket/{username}&quot;)
public class BasketResource {
  @PathParam(&quot;username&quot;) String username;
 
  @GET
  @Path(&quot;/{product}&quot;)
  public Response get(@PathParam(&quot;product&quot;) long productId) {
    Map&lt;Long, Integer&gt; quantityByProductId = Purchases.get(username);
    Stock stock = new Stock();
    stock.setId(productId);
    stock.setQuantity(quantityByProductId.get(productId));
    return Response.ok(stock).build();
  }
}
</pre><h3><a
name="TestsStocks"></a>Tests stock</h3><p>Pour incrémenter le stock d&#8217;un produit, son id est nécessaire ; mais, comme il est généré côté serveur, il est nécessaire de le récupérer lors de sa création. Par convention, POST retourne toujours l&#8217;objet qui lui est soumis décoré au minimum d&#8217;un identifiant. La création d&#8217;un produit, présentée en tête de cet article, s&#8217;appuie sur la classe utilitaire Products associant un id au produit avant de retourner le produit ainsi identifié au client. Voici le cas de test du stock.</p><pre class="brush: java; title: ; notranslate">
public class ProductResourceTest {
  @Before
  public void before() {
    for (Product product : Shipments.products()) {
      product = productResource().entity(product).post(Product.class);
      Stock stock = new Stock();
      stock.setQuantity(2);
      stockResource(product.getId()).post(stock);
    }
  }
 
  private WebResource stockResource(long productId) {
    URI uri = UriBuilder.fromPath(&quot;resource/product/{id}/stock&quot;).build(productId);
    return Client.create().resource(server.uri()).path(uri.getPath());
  }
}
</pre><p>Ce code reprend l&#8217;initialisation précédente et ajoute, pour chaque produit, un stock de 2 unités. Les produits ayant désormais du stock il est possible de tester leur réservation dans le panier d&#8217;un client.</p><pre class="brush: java; title: ; notranslate">
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.xebia.representation.Rels;
 
public class ProductResourceTest {
  @Test
  public void shouldAccessStock() {
    for (Product product : getProducts())
      assertEquals(2, stockResource(product.getId()).get(Stock.class).getQuantity());
  }
 
  @Test
  public void shouldMoveProductToBasket() {
    String username = &quot;xebia&quot;;
    int quantity = 2;
 
    Product product = getProducts().get(0);
    String uriBook = rels(product.getLinks()).get(Rels.RELS_BOOK);
    resource(uriBook, ImmutableMap.of(&quot;quantity&quot;, quantity, &quot;username&quot;, username)).post();
 
    assertEquals(0, stockResource(product.getId()).get(Stock.class).getQuantity());
    assertEquals(quantity, basketResource(username, product.getId()).get(Stock.class).getQuantity());
  }
 
  /* helpers */
 
  private WebResource resource(String href, Map&lt;String, ?&gt; params) {
    URI uri = UriBuilder.fromPath(href).buildFromMap(params);
    return resource(uri.getPath());
  }
 
  private List&lt;Product&gt; getProducts() {
    ClientResponse clientResponse = productResource().get(ClientResponse.class);
    return clientResponse.getEntity(new GenericType&lt;List&lt;Product&gt;&gt;() {});
  }
 
  private Map&lt;Rels, String&gt; rels(List&lt;Link&gt; links) {
    Map&lt;Rels, String&gt; rels = Maps.newHashMap();
    for (Link link : links)
      rels.put(link.getRel(), link.getHref());
    return rels;
  }
 
  private WebResource basketResource(String username, long productId) {
    URI uri = UriBuilder.fromPath(&quot;resource/basket/{user}/{id}&quot;).build(username, productId);
    return createClient().resource(server.uri()).path(uri.getPath());
  }
}
</pre><p>On notera l&#8217;utilisation du lien de réservation, <code>rels/book</code>, proposé par la ressource stock limitant la connaissance du client à la template (quantity, username) qu&#8217;il doit poster. En l&#8217;absence d&#8217;un article par exemple, ce lien peut disparaitre, mettant le client — ignorant l&#8217;URI complète — dans l&#8217;impossibilité d&#8217;effectuer une réservation. Ainsi l&#8217;état de l&#8217;application et ses possibilités futures sont exprimées par ces relations hypermédia (<a
href="http://blogs.oracle.com/craigmcc/entry/why_hateoas">HATEOAS</a>). Client et serveur partagent la connaissance des transitions, celles-ci étant rendues disponibles par le serveur lors de l&#8217;accès aux ressources. Le couplage obtenu entre client et serveur en est ainsi affaibli.</p><p>Le panier propose des relations afin d&#8217;accéder à chaque article réservé (la relation related est souvent utilisé à des fins d&#8217;économie de ce genre) au prix total et au paiement. Un client, après avoir accédé à une ressource, navigue grâce aux relations communiquées par cette dernière aux ressources suivantes. Le code clé-en-main <a
href="https://github.com/yamsellem/Backbone-Jersey">disponible sur GitHub</a> couvre le paiement et la rupture du stock, afin de prolonger le sujet.</p><h3><a
name="Epilogue"></a>Épilogue</h3><p>Implémenter REST avec Jersey résulte en un code compact, élégant, explicite et indépendant du médiatype. Le cache, la sécurité et la concurrence sont supportés dans le même esprit de simplicité. Quelques considérations sur le sujet ; comme le nom d&#8217;un auteur littéraire à succès, les URI publiques gagnent à ne pas changer. Divulger le minimum d&#8217;URI, en offrant un jeu de relations riches au client, masque la complexité du serveur ; les clients agissant en fonction de relations, modifier la logique du serveur est alors peu impactant et réduit le recours au versionning.</p><p>L&#8217;implémentation d&#8217;un client JavaScript communiquant avec le serveur développé ici, réalisée dans l&#8217;article connexe consacré au sujet, est l&#8217;occasion d&#8217;apprécier davantage les vertus de l&#8217;interface uniforme de HTTP. Le livre <a
href="http://books.google.com/books?id=LDuzpQlVuG4C&#038;printsec=frontcover&#038;hl=fr#v=onepage&#038;q&#038;f=true">RESTful Web Services Cookbook</a> est un excellent moyen de se plonger davantage encore sur la question.</p><div
class="shr-publisher-9033"></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div><div
class='shareaholic-like-buttonset' style='float:none;height:30px;'><a
class='shareaholic-googleplusone' data-shr_size='medium' data-shr_count='true' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2011%2F11%2F14%2Frest-java-serveur%2F' data-shr_title='REST+c%C3%B4t%C3%A9+serveur+avec+Java'></a><a
class='shareaholic-tweetbutton' data-shr_count='horizontal' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2011%2F11%2F14%2Frest-java-serveur%2F' data-shr_title='REST+c%C3%B4t%C3%A9+serveur+avec+Java'></a></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div>]]></content:encoded> <wfw:commentRss>http://blog.xebia.fr/2011/11/14/rest-java-serveur/feed/</wfw:commentRss> <slash:comments>1</slash:comments> </item> <item><title>JAXB, le parsing XML — objet</title><link>http://blog.xebia.fr/2011/03/17/jaxb-le-parsing-xml-objet/</link> <comments>http://blog.xebia.fr/2011/03/17/jaxb-le-parsing-xml-objet/#comments</comments> <pubDate>Thu, 17 Mar 2011 06:00:47 +0000</pubDate> <dc:creator>Yves Amsellem</dc:creator> <category><![CDATA[Java / JEE]]></category> <category><![CDATA[SOA]]></category> <category><![CDATA[Data Binding]]></category> <category><![CDATA[DOM]]></category> <category><![CDATA[JAX-RS]]></category> <category><![CDATA[JAXB]]></category> <category><![CDATA[XML]]></category> <category><![CDATA[XPath]]></category> <category><![CDATA[XSD]]></category> <guid
isPermaLink="false">http://blog.xebia.fr/?p=7163</guid> <description><![CDATA[Format privilégié pour les échanges inter-applications, XML est l&#8217;objet de nombreuses bibliothèques Java. Cependant, ces bibliothèques masquent toutes le data binding qu&#8217;elles effectuent ; la transformation d&#8217;un document XML en grappe d&#8217;objets. Nous voilà bien démunis dès lors qu&#8217;une application produit du XML comme une simple chaîne de caractères. L&#8217;utilisation d&#8217;API bas niveau (DOM, XPath) [...]]]></description> <content:encoded><![CDATA[<p>Format privilégié pour les échanges inter-applications, XML est l&#8217;objet de nombreuses bibliothèques Java. Cependant, ces bibliothèques masquent toutes le data binding qu&#8217;elles effectuent ; la transformation d&#8217;un document XML en grappe d&#8217;objets. Nous voilà bien démunis dès lors qu&#8217;une application produit du XML comme une simple chaîne de caractères. L&#8217;utilisation d&#8217;API bas niveau (DOM, XPath) — attachées à la structure du document — se révélant fastidieuse, la majorité des implémentations JAX-RS (Jersey, CXF) ont retenu la même API de haut niveau — concentrée sur les données — : <strong>JAXB</strong>. Faisons de même.</p><ul><li><a
href="http://blog.xebia.fr/2011/03/17/jaxb-le-parsing-xml-objet/#Decrire">Décrire un format d&#8217;échange</a></li><li><a
href="http://blog.xebia.fr/2011/03/17/jaxb-le-parsing-xml-objet/#Raffiner">Raffiner le format d&#8217;échange</a></li><li><a
href="http://blog.xebia.fr/2011/03/17/jaxb-le-parsing-xml-objet/#Epilogue">Épilogue : un contrat d&#8217;échange côté serveur</a></li></ul><h3><a
name="Decrire"></a>Décrire un format d&#8217;échange</h3><p>Lorsqu&#8217;une application produisant du XML n&#8217;a pas de mécanisme pour partager l&#8217;agencement de ses noeuds, il incombe à ses consommateurs de retenir une méthode pour l&#8217;exploiter au mieux. Cela peut être réalisé via une grappe d&#8217;objets équivalente à la sortie XML ; voyons comment à l&#8217;aide d&#8217;un dessert savoureux.</p><pre class="brush: xml; title: ; notranslate">
&lt;recipe name=&quot;Compote de poires&quot; type=&quot;dessert&quot;&gt;
    &lt;cooking duration=&quot;15&quot;&gt;
    	&lt;step optional=&quot;true&quot;&gt;Réserver une gousse de vanille&lt;/step&gt;
        &lt;step&gt;Éplucher et évider les poires&lt;/step&gt;
        &lt;step&gt;Découper les poires en quartiers&lt;/step&gt;
        &lt;step&gt;Verser les quartiers dans une casserole avec l'eau&lt;/step&gt;
    &lt;/cooking&gt;
    &lt;menu&gt;17-02-2011&lt;/menu&gt;
    &lt;menu&gt;17-03-2011&lt;/menu&gt;
&lt;/recipe&gt;
</pre><p>JAXB identifie chaque noeud comme un <em>élément</em> doté <em>d&#8217;attributs</em>. Un élément est un type complexe doté d&#8217;une séquence d&#8217;éléments (toujours en premier) puis d&#8217;une liste d&#8217;attributs. Un élément peut porter une simple valeur textuelle lorsqu&#8217;il n&#8217;a pas de sous-noeuds. Un attribut ne dispose que d&#8217;une valeur textuelle. Chaque noeud XML est représenté par un élément du schéma puis, à l&#8217;aide de XJC, par un objet du même nom généré à partir de ce schéma (la génération XJC est abordée en annexe).</p><p>Voici la description du XML précédent à l&#8217;aide d&#8217;un XSD :</p><pre class="brush: xml; title: ; notranslate">
&lt;xsd:schema xmlns:xsd=&quot;http://www.w3.org/2001/XMLSchema&quot;&gt;
    &lt;xsd:element name=&quot;recipe&quot;&gt;
        &lt;xsd:complexType&gt;
            &lt;xsd:sequence&gt;
                &lt;xsd:element name=&quot;menu&quot; type=&quot;xsd:string&quot; maxOccurs=&quot;unbounded&quot; /&gt;
                &lt;xsd:element name=&quot;cooking&quot; type=&quot;cooking&quot; /&gt;
            &lt;/xsd:sequence&gt;
            &lt;xsd:attribute name=&quot;name&quot; type=&quot;xsd:string&quot; /&gt;
            &lt;xsd:attribute name=&quot;type&quot; type=&quot;xsd:string&quot; /&gt;
        &lt;/xsd:complexType&gt;
    &lt;/xsd:element&gt;
    &lt;xsd:complexType name=&quot;cooking&quot;&gt;
        &lt;xsd:sequence&gt;
            &lt;xsd:element name=&quot;step&quot; type=&quot;step&quot; maxOccurs=&quot;unbounded&quot; /&gt;
        &lt;/xsd:sequence&gt;
        &lt;xsd:attribute name=&quot;duration&quot; type=&quot;xsd:int&quot; /&gt;
    &lt;/xsd:complexType&gt;
    &lt;xsd:complexType name=&quot;step&quot; mixed=&quot;true&quot;&gt;
        &lt;xsd:attribute name=&quot;optional&quot; type=&quot;xsd:boolean&quot; /&gt;
    &lt;/xsd:complexType&gt;
&lt;/xsd:schema&gt;
</pre><p>Les noeuds de ce schéma sont tous précédés de « xsd » car leur définition, sur la première ligne, nomme le XML Namespace (xmlns) ainsi. Les namespaces sont une manière de différentier les déclarations des imports d&#8217;en-tête les uns des autres, comme le ferrait un package en java.</p><p>Les variables sont typées selon <a
href="http://www.w3.org/TR/xmlschema-0/#CreatDt" title="la recommandation w3c" target="_blank">la recommandation w3c</a>. Lorsqu&#8217;une liste de types primitifs est nécessaire (noeud menu) sa déclaration n&#8217;occasionnera pas la création d&#8217;une classe, seulement d&#8217;un attribut typé. En revanche si cette liste dispose d&#8217;attributs (noeud step), il est nécessaire d&#8217;indiquer que son contenu est mixte : par défaut les éléments ont soit une valeur textuelle, soit une liste d&#8217;attributs et d&#8217;éléments, pas les deux.</p><p>Voici le code généré à partir du schéma précédent :</p><pre class="brush: java; title: ; notranslate">
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = &quot;recipe&quot;)
public class Recipe {
    protected List&lt;String&gt; menu;
    protected Cooking cooking;
    @XmlAttribute
    protected String name;
    @XmlAttribute
    protected String type;
}
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = &quot;cooking&quot;)
public class Cooking {
    protected List&lt;Step&gt; step;
    @XmlAttribute
    protected Integer duration;
}
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = &quot;step&quot;)
public class Step {
    @XmlValue
    protected String content;
    @XmlAttribute
    protected Boolean optional;
}
</pre><p>Seule une classe est annotée @XmlRootElement. Elle est la seule (dans ce schéma) à pouvoir jouer le rôle de premier noeud. Une fois la grappe résultat générée, 3 lignes de code suffisent à réaliser le parsing XML :</p><pre class="brush: java; title: ; notranslate">
public class JaxbTest {
    @Test
    public void should_parse_recipe() throws JAXBException {
        URL xmlUrl = Resources.getResource(&quot;recipe.xml&quot;);
        Recipe recipe = parse(xmlUrl, Recipe.class);
        assertEquals(Integer.valueOf(15), recipe.getCooking().getDuration());
    }
    private &lt;T&gt; T parse(URL url, Class&lt;T&gt; clazz) throws JAXBException {
        Unmarshaller unmarshaller = JAXBContext.newInstance(clazz).createUnmarshaller();
        return clazz.cast(unmarshaller.unmarshal(url));
    }
}
</pre><p>Contrairement aux bibliothèques de bas niveau, aucune conversion de type n&#8217;est nécessaire. La déclaration du type dans le schéma suffit à nous affranchir de cette responsabilité. En cas d&#8217;erreur de conversion (une chaine non convertible dans le type attendu) l&#8217;IllegalArgumentException correspondante est levée. En l&#8217;absence d&#8217;un noeud, les variables correspondantes sont null.</p><h3><a
name="Raffiner"></a>Raffiner le format d&#8217;échange</h3><p>Une fois un data binding réussi, plusieurs opérations sont couramment nécessaires :</p><ol><li>limiter un champ à un ensemble fini de valeurs ;</li><li>manipuler des dates plus simples que le XMLGregorianCalendar manipulé par défaut par JAXB ;</li><li>nommer une classe différemment de l&#8217;élément qu&#8217;elle représente ;</li><li>utiliser l&#8217;héritage entre éléments ;</li><li>annoter manuellement des classes existantes.</li></ol><h4><a
name="Limiter"></a>Limiter un champ à un ensemble fini de valeurs</h4><p>Limiter l&#8217;attribut « type » de recette à « entrée, plat, dessert » peut être fait de la façon suivante :</p><pre class="brush: xml; title: ; notranslate">
&lt;xsd:element name=&quot;recipe&quot;&gt;
    &lt;xsd:attribute name=&quot;type&quot; type=&quot;formule&quot; /&gt;
&lt;/xsd:element&gt;
&lt;xsd:simpleType name=&quot;formule&quot;&gt;
    &lt;xsd:restriction base=&quot;xsd:string&quot;&gt;
        &lt;xsd:enumeration value=&quot;entree&quot;&gt;&lt;/xsd:enumeration&gt;
        &lt;xsd:enumeration value=&quot;plat&quot;&gt;&lt;/xsd:enumeration&gt;
        &lt;xsd:enumeration value=&quot;dessert&quot;&gt;&lt;/xsd:enumeration&gt;
    &lt;/xsd:restriction&gt;
&lt;/xsd:simpleType&gt;
</pre><p>Ce qui donne, une fois généré :</p><pre class="brush: java; title: ; notranslate">
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = &quot;recipe&quot;)
public class Recipe {
    @XmlAttribute
    protected Formule type;
}
@XmlEnum
public enum Formule {
    @XmlEnumValue(&quot;entree&quot;)
    ENTREE(&quot;entree&quot;),
    @XmlEnumValue(&quot;plat&quot;)
    PLAT(&quot;plat&quot;),
    @XmlEnumValue(&quot;dessert&quot;)
    DESSERT(&quot;dessert&quot;);
    private final String value;
}
</pre><p>Lors du binding, s&#8217;il s&#8217;avérait que la valeur du champ ne corresponde pas à l&#8217;une de celles spécifiées ici, la valeur null serait retournée. JAXB fait le choix de positionner ses variables à null en cas de problème de valeur. Les problèmes de typage, eux, lèvent tous une exception.</p><h4><a
name="Manipuler"></a>Manipuler des dates simples</h4><p>Pour manipuler des dates Java en lieu et place du XMLGregorianCalendar utilisé par défaut par JAXB, un convertisseur va être nécessaire. Attention, un nouveau namespace est nécessaire à sa déclaration. Il permet de redéfinir le typage de JAXB.</p><pre class="brush: xml; title: ; notranslate">
&lt;xsd:schema xmlns:xsd=&quot;http://www.w3.org/2001/XMLSchema&quot;
            xmlns:jxb=&quot;http://java.sun.com/xml/ns/jaxb&quot;
            jxb:version=&quot;2.0&quot;&gt;
    &lt;xsd:annotation&gt;&lt;xsd:appinfo&gt;
        &lt;jxb:globalBindings&gt;
            &lt;jxb:javaType name=&quot;java.util.Date&quot; xmlType=&quot;xsd:dateTime&quot;
                          parseMethod=&quot;com.xebia.jaxb.JaxbDateConverter.parseDateTime&quot; /&gt;
        &lt;/jxb:globalBindings&gt;
    &lt;/xsd:appinfo&gt;&lt;/xsd:annotation&gt;
    &lt;xsd:element name=&quot;menu&quot; type=&quot;xsd:dateTime&quot; /&gt;
&lt;/xsd:schema&gt;
</pre><p>Le convertisseur doit respecter la logique JAXB, si la valeur en entrée ne convient pas, aucune exception n&#8217;est levée et la valeur null est renvoyée.</p><pre class="brush: java; title: ; notranslate">
public class JaxbDateConverter {
    public static Date parseDateTime(String s) {
        DateFormat formatter = new SimpleDateFormat(&quot;dd-MM-yyyy&quot;);
        try {
            return formatter.parse(s);
        } catch (ParseException e) {
            return null;
        }
    }
}
</pre><p>Lors de la génération, JAXB crée une classe adapter qu&#8217;il lie aux méthodes statiques du converter.</p><pre class="brush: java; title: ; notranslate">
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = &quot;recipe&quot;)
public class Recipe {
    @XmlElement(type = String.class)
    @XmlJavaTypeAdapter(Adapter1.class)
    @XmlSchemaType(name = &quot;dateTime&quot;)
    protected List&lt;Date&gt; menu;
</pre><h4><a
name="Nommer"></a>Nommer une classe différemment de l&#8217;élément qu&#8217;elle représente</h4><p>Pour nommer une classe différemment de l&#8217;élément qu&#8217;elle représente, il suffit d&#8217;ajouter les modifications suivantes à un schéma (attention à bien indiquer les deux namespaces) :</p><pre class="brush: xml; title: ; notranslate">
&lt;xsd:element name=&quot;menu&quot; type=&quot;xsd:dateTime&quot; /&gt;
&lt;xsd:annotation&gt;&lt;xsd:appinfo&gt;
    &lt;jxb:class name=&quot;meal&quot; /&gt;
&lt;/xsd:appinfo&gt;&lt;/xsd:annotation&gt;
</pre><h4><a
name="Utiliser"></a>Utiliser l&#8217;héritage entre éléments</h4><p>Utiliser l&#8217;héritage entre objet est aisé (les objets générés hériteront l&#8217;un de l&#8217;autre, bien entendu) :</p><pre class="brush: xml; title: ; notranslate">
&lt;xsd:complexType name=&quot;menuxl&quot;&gt;
    &lt;xsd:complexContent&gt;
        &lt;xsd:extension base=&quot;menu&quot; /&gt;
    &lt;/xsd:complexContent&gt;
    &lt;xsd:attribute name=&quot;cook&quot; type=&quot;xsd:string&quot; /&gt;
&lt;/xsd:complexType&gt;
</pre><h4><a
name="Annoter"></a>Annoter manuellement des classes existantes</h4><p>Jusqu&#8217;ici nous avons fait reposer les objets d&#8217;échange sur une génération à l&#8217;aide d&#8217;un schéma. Annoter manuellement une classe en vue de lui binder du XML est également possible. Le schema correspondant peut même être généré à posteriori à partir des sources.</p><p>L&#8217;utilisation d&#8217;annotations manuelles permet d&#8217;avoir un controle plus fin sur la grappe d&#8217;objets, leur type et, pourquoi pas, d&#8217;utiliser des objets déjà utiles par ailleurs (ajouter un champ non concerné par le binding se fait à l&#8217;aide @XmlTransient).</p><p>Afin de respecter la logique JAXB, il est toutefois nécessaire de modifier les accesseurs des listes. Par convention, en l&#8217;absence de valeur, le code généré retourne des listes vides plutôt que null. JAXB, lors de la génération d&#8217;objets effectue cela via la modification des getters. Il est recommandé de faire de même.</p><pre class="brush: java; title: ; notranslate">
public List&lt;String&gt; getMenu() {
    if (menu == null) {
        menu = new ArrayList&lt;String&gt;();
    }
    return menu;
}
</pre><h3><a
name="Epilogue"></a>Épilogue : un contrat d&#8217;échange côté serveur</h3><p>Jusqu&#8217;ici nous avons considéré qu&#8217;aucun mécanisme décrivant l&#8217;agencement des noeuds XML n&#8217;était fourni du producteur aux consommateurs ; qu&#8217;il était résolu à postériori par ces derniers. Il est préférable, lorsque c&#8217;est possible, de les affranchir de cette contrainte en leur communiquant le schéma avec les données.</p><p>Pour ce faire, il est judicieux d&#8217;opter pour un mode de développement dirigé par le contrat. Générer les objets — côté serveur — de la couche d&#8217;échange au lieu de les annoter limite le couplage entre le schéma et son implémentation. Se restreindre aux possibilités de typage et d&#8217;agencement d&#8217;un schéma XSD garantit la compatibilité du format à tout type de consommateur (notamment autre que java). <a
href="http://static.springsource.org/spring-ws/site/reference/html/why-contract-first.html" title="La documentation de rfrence Spring" target="_blank">La documentation de référence Spring</a> détaille ce propos en l&#8217;illustrant.</p><h3><a
name="Annexe"></a>Annexe : outillage</h3><p>Afin d&#8217;effectuer les manipulations présentées ici deux outils sont nécessaires, <a
href="http://mvnrepository.com/artifact/com.sun.xml.bind/jaxb-impl" title="la dépendance maven de JAXB" target="_blank">la dépendance maven de JAXB</a> et <a
href="http://mojo.codehaus.org/jaxb2-maven-plugin/usage.html" title="le plugin de gnration associ" target="_blank">le plugin de génération associé</a> dont voici une version simple (exécutable via <strong>mvn jaxb2:xjc</strong>) :</p><pre class="brush: xml; title: ; notranslate">
&lt;plugin&gt;
    &lt;groupId&gt;org.codehaus.mojo&lt;/groupId&gt;
    &lt;artifactId&gt;jaxb2-maven-plugin&lt;/artifactId&gt;
    &lt;configuration&gt;
    	&lt;outputDirectory&gt;${basedir}/src/main/java&lt;/outputDirectory&gt;
    	&lt;schemaDirectory&gt;${basedir}/src/main/resources/xsd&lt;/schemaDirectory&gt;
    	&lt;packageName&gt;com.xebia.jaxb.generated&lt;/packageName&gt;
    	&lt;schemaFiles&gt;schema.xsd&lt;/schemaFiles&gt;
    &lt;/configuration&gt;
&lt;/plugin&gt;
</pre><p>Pour prolonger l&#8217;aventure du data binding avec JAXB, <a
href="http://jaxb.java.net/tutorial" title="une riche documentation est disponible en ligne" target="_blank">une riche documentation est disponible en ligne</a>.</p><div
class="shr-publisher-7163"></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div><div
class='shareaholic-like-buttonset' style='float:none;height:30px;'><a
class='shareaholic-googleplusone' data-shr_size='medium' data-shr_count='true' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2011%2F03%2F17%2Fjaxb-le-parsing-xml-objet%2F' data-shr_title='JAXB%2C+le+parsing+XML+%E2%80%94+objet'></a><a
class='shareaholic-tweetbutton' data-shr_count='horizontal' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2011%2F03%2F17%2Fjaxb-le-parsing-xml-objet%2F' data-shr_title='JAXB%2C+le+parsing+XML+%E2%80%94+objet'></a></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div>]]></content:encoded> <wfw:commentRss>http://blog.xebia.fr/2011/03/17/jaxb-le-parsing-xml-objet/feed/</wfw:commentRss> <slash:comments>3</slash:comments> </item> <item><title>Créer un composant Apache Camel de connexion à l’APNS – 3 sur 3</title><link>http://blog.xebia.fr/2010/10/13/creer-un-composant-apache-camel-de-connexion-a-lapns-3-sur-3/</link> <comments>http://blog.xebia.fr/2010/10/13/creer-un-composant-apache-camel-de-connexion-a-lapns-3-sur-3/#comments</comments> <pubDate>Wed, 13 Oct 2010 21:07:31 +0000</pubDate> <dc:creator>Alexis Kinsella</dc:creator> <category><![CDATA[Java / JEE]]></category> <category><![CDATA[SOA]]></category> <category><![CDATA[Apple]]></category> <category><![CDATA[Camel]]></category> <guid
isPermaLink="false">http://blog.xebia.fr/?p=5625</guid> <description><![CDATA[Nous avons vu dans un premier article comment initier le développement d&#8217;un composant Apache Camel, puis dans un second comment implémenter ses différentes classes. A ce stade de notre développement nous sommes déjà en mesure d&#8217;utiliser pleinement notre composant, mais nous ne pouvons pas encore en assurer sa qualité. Pour cela, il est nécessaire d&#8217;ajouter [...]]]></description> <content:encoded><![CDATA[<p>Nous avons vu dans un <a
href="http://blog.xebia.fr/2010/09/30/creer-un-composant-apache-camel-de-connexion-a-lapns-1-sur-3/" title="premier article" >premier article</a> comment initier le développement d&#8217;un composant Apache Camel, puis dans un <a
href="http://blog.xebia.fr/2010/10/06/creer-un-composant-apache-camel-de-connexion-a-lapns-2-sur-3/" title="second article" >second</a> comment implémenter ses différentes classes.</p><p>A ce stade de notre développement nous sommes déjà en mesure d&#8217;utiliser pleinement notre composant, mais nous ne pouvons pas encore en assurer sa qualité. Pour cela, il est nécessaire d&#8217;ajouter à notre composant différentes classes de test. Bien que la testabilité de frameworks d&#8217;intégration puisse parfois paraître difficile, le projet Apache Camel fournit tous les outils nécessaires permettant de répondre à ce besoin. Nous verrons donc dans cet article comment tester le composant que nous avons développé.</p><p>Pour finir, nous verrons comment intégrer notre développement à un projet Camel, ainsi que les limites de notre composant et les solutions pour résoudre ces limitations.</p><h3><a
name="TesterlaclasseApnsConsumer"></a>Tester la classe ApnsConsumer</h3><p>Bien que le projet Apache Camel permette de travailler naturellement avec Spring, nous nous attarderons dans un premier temps sur les méthodes permettant de tester notre composant sur un mode standalone. Pour cela, nous étendrons la classe <em>CamelTestSupport</em>. Cette dernière fournit les méthodes nécessaires pour effectuer différentes assertions sur les valeurs attendues en fin de traitement, en particulier sur des endpoints de type <em>MockEndpoint</em>.</p><p>Nous devons tout d&#8217;abord implémenter les 2 méthodes suivantes:</p><table
class="tablo"><thead><th> Méthode</th><th> Description</th></thead><tbody><tr><td> createCamelContext()</td><td> Permet de créer le contexte Camel qui sera utilisé par le test</td></tr><tr><td> createRouteBuilder()</td><td> Permet de construire la route qui sera appelée par le test. Idéalement, la route doit se terminer par l&#8217;appel d&#8217;un MockEpoint</td></tr></tbody></table><p>Avant l&#8217;exécution de nos tests, un serveur APNS bouchonné doit être lancé. Il enverra sur le flux feedback des données factices.</p><p>L&#8217;objectif de ce test est de valider que le endpoint <em>apns:consumer</em> est capable de consommer les informations de test renvoyées par le flux feedback du serveur bouchonné. Le endpoint Camel <em>mock:result</em> nous permet de valider les assertions nécessaires sur les messages reçus par ce endpoint.</p><p>Le endpoint <em>apns:consumer</em> est configuré pour poller le flux feedback de l&#8217;APNS toutes les 500ms. Le test ne doit donc pas durer raisonnablement plus de 5 secondes en tenant compte du temps d&#8217;attente d&#8217;une seconde avant les assertions et du temps de démarrage du serveur bouchon APNS. Un timeout de 5 secondes est donc placé sur le test pour s&#8217;assurer que ce dernier tombe en erreur si un événement bloquant inattendu empêche le test de se terminer.</p><pre class="brush: java; title: ; notranslate">
public class ApnsConsumerTest extends CamelTestSupport {
    ApnsServerStub server;
    public ApnsConsumerTest() {
    	super();
    }
    /**
     * Démarrage du serveur bouchonné simulant l'APNS
     */
    @Before
    public void startup() throws InterruptedException {
        server = ApnsServerStub.prepareAndStartServer(FixedCertificates.TEST_GATEWAY_PORT, FixedCertificates.TEST_FEEDBACK_PORT);
    }
    /**
     * Arrêt du serveur bouchonné simulant l'APNS
     */
    @After
    public void stop() {
        server.stop();
    }
    /**
     * Test de l'ApnsConsumer. L'objectif est de vérifier que le flux feedback est
     * bien consommé par la route Camel. Pour cela on vérifie après consommation
     * que le endpoint MockEndpoint a bien reçu les messages.
     */
    @Test(timeout=5000)
    public void testConsumer() throws Exception {
    	byte[] deviceTokenBytes = ApnsUtils.createRandomDeviceTokenBytes();
        String deviceToken = ApnsUtils.encodeHexToken(deviceTokenBytes);
        MockEndpoint mock = getMockEndpoint(&quot;mock:result&quot;);
        mock.expectedMessageCount(1);
        mock.message(0).body().isInstanceOf(InactiveDevice.class);
        byte[] feedBackBytes = ApnsUtils.generateFeedbackBytes(deviceTokenBytes);
        server.toSend.write(feedBackBytes);
        Thread.sleep(1000);
        assertMockEndpointsSatisfied();
        InactiveDevice inactiveDevice = (InactiveDevice)mock.getExchanges().get(0).getIn().getBody();
        assertNotNull(inactiveDevice);
        assertNotNull(inactiveDevice.getDate());
        assertNotNull(inactiveDevice.getDeviceToken());
        assertEquals(deviceToken, inactiveDevice.getDeviceToken());
    }
    /**
     * Création et configuration du contexte Camel avec une configuration de test.
     * Enregistrement du composant APNS, et configuration de l'ApnsService
     */
    protected CamelContext createCamelContext() throws Exception {
        CamelContext camelContext = super.createCamelContext();
        ApnsServiceFactory apnsServiceFactory = ApnsUtils.createDefaultTestConfiguration();
        ApnsService apnsService = apnsServiceFactory.getApnsService();
        ApnsComponent apnsComponent = new ApnsComponent(apnsService);
        camelContext.addComponent(&quot;apns&quot;, apnsComponent);
        return camelContext;
    }
    /**
     * Création de la route Camel permettant de simuler la consommation du flux
     * feedback de l'APNS
     */
    protected RouteBuilder createRouteBuilder() throws Exception {
        return new RouteBuilder() {
            public void configure() throws Exception {
                from(&quot;apns:consumer?initialDelay=500&amp;delay=500&amp;timeUnit=MILLISECONDS&quot;)
                	.to(&quot;log:com.apache.camel.component.apns?showAll=true&amp;multiline=true&quot;)
                	.to(&quot;mock:result&quot;);
            }
        };
    }
}
</pre><h3><a
name="TesterlaclasseApnsProducer"></a>Tester la classe ApnsProducer</h3><p>De la même façon que nous nous y sommes pris pour la classe de test <em>ApnsConsumerTest</em>, nous allons étendre la classe <em>CamelTestSupport</em> pour tester notre classe <em>ApnsProducer</em>. L&#8217;objectif est de vérifier que le serveur bouchonné reçoit bien les messages produits.</p><pre class="brush: java; title: ; notranslate">
public class ApnsProducerTest extends CamelTestSupport {
    private ApnsServerStub server;
    private String FAKE_TOKEN = &quot;19308314834701ACD8313AEBD92AEFDE192120371FE13982392831701318B943&quot;;
    public ApnsProducerTest() {
    	super();
    }
    /**
     * Démarrage du serveur bouchonné simulant l'APNS
     */
    @Before
    public void startup() {
        server = ApnsServerStub.prepareAndStartServer(FixedCertificates.TEST_GATEWAY_PORT, FixedCertificates.TEST_FEEDBACK_PORT);
    }
    /**
     * Arrêt du serveur bouchonné simulant l'APNS
     */
    @After
    public void stop() {
        server.stop();
    }
    /**
     * Test de l'ApnsProducer. L'objectif est de vérifier que le serveur APNS a
     * bien reçu les notifications envoyées.
     * Pour cela on vérifie après production des notifications que le serveur bouchonné
     * a bien reçu les messages: On s'assure que les tableaux de bytes de la notification
     * produite et du contenu reçu par le serveur sont bien égaux.
     */
    @Test(timeout=2000)
    public void testProducer() throws Exception {
    	String message = &quot;Hello World&quot;;
    	String messagePayload = APNS.newPayload().alertBody(message).build();
        ApnsNotification apnsNotification = new ApnsNotification(FAKE_TOKEN, messagePayload);
        server.stopAt(apnsNotification.length());
        template.sendBody(&quot;direct:test&quot;, message);
        server.messages.acquire();
        assertArrayEquals(apnsNotification.marshall(), server.received.toByteArray());
    }
    /**
     * Création et configuration du contexte Camel avec une configuration de test.
     * Enregistrement du composant APNS, et configuration de l'ApnsService
     */
    protected CamelContext createCamelContext() throws Exception {
        CamelContext camelContext = super.createCamelContext();
        ApnsServiceFactory apnsServiceFactory = ApnsUtils.createDefaultTestConfiguration();
        ApnsService apnsService = apnsServiceFactory.getApnsService();
        ApnsComponent apnsComponent = new ApnsComponent(apnsService);
        camelContext.addComponent(&quot;apns&quot;, apnsComponent);
        return camelContext;
    }
    /**
     * Création de la route Camel permettant de simuler la production de messages
     * à destination des serveurs APNS.
     */
    protected RouteBuilder createRouteBuilder() throws Exception {
        return new RouteBuilder() {
            public void configure() throws Exception {
                from(&quot;direct:test&quot;).
                setHeader(ApnsConstants.HEADER_TOKENS, constant(FAKE_TOKEN)).
                to(&quot;apns:notify&quot;);
            }
        };
    }
}
</pre><h3><a
name="TesterlintgrationduncomposantC"></a>Tester l&#8217;intégration d&#8217;un composant Camel avec Spring</h3><p>Les configurations Camel sont souvent déclarées par des fichiers de configuration Spring. C&#8217;est pourquoi il est nécessaire de tester l&#8217;intégration du composant dans une configuration Spring. Un bon moyen d&#8217;automatiser ce type de test est d&#8217;utiliser les classes de support JUnit fournies par Spring ( _AbstractJUnit4SpringContextTests_ ).</p><p>L&#8217;ensemble de la configuration est déclarée dans le fichier <em>SpringApnsConsumerTest-context.xml</em> associé au test unitaire. Les différents beans utilisés par la classe de test sont injectés via les annotations <em>@Autowired</em> et <em>@EndpointInject(uri = &laquo;&nbsp;mock:result&nbsp;&raquo;)</em>.</p><pre class="brush: xml; title: ; notranslate">
&lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
       xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
       xmlns:camel=&quot;http://camel.apache.org/schema/spring&quot;
       xsi:schemaLocation=&quot;
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
        http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd&quot;&gt;
	&lt;bean id=&quot;apnsServiceFactory&quot; class=&quot;org.apache.camel.component.apns.factory.ApnsServiceFactory&quot;&gt;
		&lt;property name=&quot;feedbackHost&quot; value=&quot;localhost&quot; /&gt;
		&lt;property name=&quot;feedbackPort&quot; value=&quot;7843&quot; /&gt;
		&lt;property name=&quot;gatewayHost&quot; value=&quot;localhost&quot; /&gt;
		&lt;property name=&quot;gatewayPort&quot; value=&quot;7654&quot; /&gt;
		&lt;property name=&quot;sslContext&quot; ref=&quot;sslContext&quot; /&gt;
	&lt;/bean&gt;
	&lt;!-- Déclaration de l'ApnsService, utilisé par l'ApnsComponent --&gt;
	&lt;bean id=&quot;apnsService&quot; factory-bean=&quot;apnsServiceFactory&quot; factory-method=&quot;getApnsService&quot; /&gt;
	&lt;bean id=&quot;sslContext&quot; class=&quot;org.apache.camel.component.apns.util.FixedCertificates&quot; factory-method=&quot;clientContext&quot;/&gt;
	&lt;!-- Déclaration de l'ApnsComponent. Le scheme utilisé pour la création des endpoints --&gt;
	&lt;!-- sera l'Id utilisé pour la création du bean --&gt;
	&lt;bean id=&quot;apns&quot; class=&quot;org.apache.camel.component.apns.ApnsComponent&quot;&gt;
		&lt;property name=&quot;apnsService&quot; ref=&quot;apnsService&quot; /&gt;
	&lt;/bean&gt;
	&lt;!-- Déclaration du context Camel, et de la route de test: 'apns-test' --&gt;
	&lt;!-- Les message reçus par le flux feedback seront envoyés vers le endpoint mock:result --&gt;
	&lt;camelContext id=&quot;camel-apns-test&quot; xmlns=&quot;http://camel.apache.org/schema/spring&quot;&gt;
		&lt;route id=&quot;apns-test&quot;&gt;
			&lt;from uri=&quot;apns:consumer?initialDelay=500&amp;delay=500&amp;timeUnit=MILLISECONDS&quot; /&gt;
			&lt;to uri=&quot;log:org.apache.camel.component.apns?showAll=true&amp;multiline=true&quot; /&gt;
			&lt;to uri=&quot;mock:result&quot; /&gt;
		&lt;/route&gt;
	&lt;/camelContext&gt;
&lt;/beans&gt;
</pre><p>Une fois la déclaration du composant Camel effectuée via le fichier de configuration Spring, il ne reste plus qu&#8217;à injecter les différents beans configurés dans les propriétés de la classe de test. Le contenu du test en lui-même reste identique, cependant la partie configuration a disparu ce qui rend le test plus lisible. Afin de faire disparaître du test ce qui peut encore en parasiter sa lisibilité, une classe de test parent peut être créée pour contenir les méthodes d&#8217;initialisation et d&#8217;arrêt du serveur APNS de test.</p><pre class="brush: java; title: ; notranslate">
@ContextConfiguration
public class SpringApnsConsumerTest extends AbstractJUnit4SpringContextTests {
    ApnsServerStub server;
    /**
     * Injection du context Camel déclaré via Spring
     */
    @Autowired
    protected CamelContext camelContext;
    /**
     * Injection du endpoint Camel &quot;mock:result&quot; déclaré via Spring
     */
    @EndpointInject(uri = &quot;mock:result&quot;)
    protected MockEndpoint mock;
    public SpringApnsConsumerTest() {
    	super();
    }
    /**
     * Démarrage du serveur bouchonné simulant l'APNS
     */
    @Before
    public void startup() throws InterruptedException {
        server = ApnsServerStub.prepareAndStartServer(FixedCertificates.TEST_GATEWAY_PORT, FixedCertificates.TEST_FEEDBACK_PORT);
    }
    /**
     * Arrêt du serveur bouchonné simulant l'APNS
     */
    @After
    public void stop() {
        server.stop();
    }
    /**
     * Test du consommateur
     */
    @Test(timeout=5000)
    public void testConsumer() throws Exception {
    	byte[] deviceTokenBytes = ApnsUtils.createRandomDeviceTokenBytes();
        String deviceToken = ApnsUtils.encodeHexToken(deviceTokenBytes);
        mock.expectedMessageCount(1);
        mock.message(0).body().isInstanceOf(InactiveDevice.class);
        byte[] feedBackBytes = ApnsUtils.generateFeedbackBytes(deviceTokenBytes);
        server.toSend.write(feedBackBytes);
        Thread.sleep(1000);
        mock.assertIsSatisfied();
        InactiveDevice inactiveDevice = (InactiveDevice)mock.getExchanges().get(0).getIn().getBody();
        Assert.assertNotNull(inactiveDevice);
        Assert.assertNotNull(inactiveDevice.getDate());
        Assert.assertNotNull(inactiveDevice.getDeviceToken());
        Assert.assertEquals(deviceToken, inactiveDevice.getDeviceToken());
    }
}
</pre><h3><a
name="Limitationsducomposantactuel"></a>Limitations du composant actuel</h3><p>Dans un soucis de simplicité, le composant présenté est limité fonctionnellement et ne propose qu&#8217;un ensemble réduit de fonctionnalités. L&#8217;implémentation proposée dans ce billet nous oblige à déclarer les tokens à notifier directement au niveau de la route. Cependant une implémentation plus complète pourrait permettre d&#8217;exploiter des en-têtes par exemple pour rendre la sélection de token à notifier plus dynamique.</p><p>Heureusement, la richesse du framework Apache Camel nous permet de passer outre cette restriction et d&#8217;obtenir l&#8217;aspect dynamique souhaité en utilisant le pattern <a
href="http://camel.apache.org/recipient-list.html" title="Recipient List" >Recipient List</a>, qui permet par exemple l&#8217;extraction des URIs de destination depuis un en-tête de message produit au préalable.</p><pre class="brush: java; title: ; notranslate">
RouteBuilder builder = new RouteBuilder() {
    public void configure() {
        from(&quot;direct:a&quot;).recipientList(
        header(&quot;recipientListHeader&quot;).tokenize(&quot;,&quot;));
    }
};
</pre><p>Dans cet exemple, l&#8217;en-tête <em>recipientListHeader</em> contiendrait les différentes URIs séparées par des virgules.</p><h3><a
name="Utilisationducomposantdansunpr"></a>Utilisation du composant dans un projet</h3><p>Pour utiliser le composant développé dans cette série d&#8217;articles, il suffit de l&#8217;importer en tant que dépendance Maven dans votre projet Camel et de déclarer le repository qui permettra de le charger à défaut de l&#8217;avoir déjà dans son répository local.</p><p>Ce qui donne les lignes suivantes à ajouter dans le pom de votre projet:</p><ul><li>La dépendance Maven:</li></ul><pre class="brush: xml; title: ; notranslate">
&lt;dependency&gt;
    &lt;groupId&gt;org.apache.camel&lt;/groupId&gt;
    &lt;artifactId&gt;camel-apns&lt;/artifactId&gt;
    &lt;version&gt;2.4.0&lt;/version&gt;
&lt;/dependency&gt;
</pre><ul><li>Le repository Maven qui met à disposition le composant:</li></ul><pre class="brush: xml; title: ; notranslate">
&lt;repositories&gt;
    &lt;repository&gt;
        &lt;id&gt;camel-apns.repo-release&lt;/id&gt;
        &lt;url&gt;http://camel-apns.googlecode.com/svn/maven/public/repository/release/&lt;/url&gt;
    &lt;/repository&gt;
&lt;/repositories&gt;
</pre><h3><a
name="Exemplesdutilisation"></a>Exemples d&#8217;utilisation</h3><p>Afin de donner une vision synthétique de l&#8217;usage de notre composant, voici un condensé de quelques exemples d&#8217;utilisation:</p><ul><li>Consommation du flux feedback avec une configuration Java</li></ul><pre class="brush: java; title: ; notranslate">
      from(&quot;apns:consumer&quot;)
            .to(&quot;log:com.apache.camel.component.apns?showAll=true&amp;multiline=true&quot;)
            .to(&quot;mock:result&quot;);
</pre><ul><li>Envoi de notifications avec une configuration Java</li></ul><pre class="brush: java; title: ; notranslate">
      from(&quot;direct:test&quot;)
            .setHeader(ApnsConstants.HEADER_TOKENS, constant(FAKE_TOKEN))
            to(&quot;apns:notify&quot;);
</pre><ul><li>Envoi d&#8217;une notification avec une configuration Spring</li></ul><pre class="brush: xml; title: ; notranslate">
&lt;camelContext id=&quot;camel-apns-test&quot; xmlns=&quot;http://camel.apache.org/schema/spring&quot;&gt;
	&lt;route id=&quot;apns-test&quot;&gt;
		&lt;from uri=&quot;apns:consumer&quot; /&gt;
		&lt;to uri=&quot;log:org.apache.camel.component.apns?showAll=true&amp;multiline=true&quot; /&gt;
		&lt;to uri=&quot;mock:result&quot; /&gt;
	&lt;/route&gt;
&lt;/camelContext&gt;
</pre><h3><a
name="Conclusion"></a>Conclusion</h3><p>Nous avons vu dans cet article comment créer et tester un composant Camel qui communique avec les serveurs de notifications d&#8217;Apple. Les API du framework ont été pensées pour faciliter le développement de nouveaux composants, et vous permettront d&#8217;implémenter et de tester facilement les composants dont vous avez besoin. Vous pouvez consulter le code source du composant camel-apns présenté dans cette série d&#8217;article sur sa page <a
href="http://code.google.com/p/camel-apns" title="Google code - Projet camel-apns" >Google Code</a>.</p><h3><a
name="Liensutiles"></a>Liens utiles:</h3><p>Le site google code du composant &#8216;camel-apns&#8217; présenté dans le billet:</p><ul><li><a
href="http://code.google.com/p/camel-apns" title="httpcodegooglecompcamelapns" >http://code.google.com/p/camel-apns</a></li></ul><p>D&#8217;autres liens utiles sur le développement de composants Camel:</p><ul><li><a
href="http://camel.apache.org/testing.html" title="Crer des tests unitaires Apache Camel" >Créer des tests unitaires Apache Camel</a></li><li><a
href="http://camel.apache.org/test.html" title="Tester un composant Apache Camel" >Tester un composant Apache Camel</a></li></ul><p>Précédentes parties de l&#8217;article:</p><ul><li><a
href="http://blog.xebia.fr/2010/09/30/creer-un-composant-apache-camel-de-connexion-a-lapns-1-sur-3/" title="Crer un composant Apache Camel de connexion  lAPNS  1 sur 3" >Créer un composant Apache Camel de connexion à l&#8217;APNS &#8211; 1 sur 3</a></li><li><a
href="http://blog.xebia.fr/2010/09/30/creer-un-composant-apache-camel-de-connexion-a-lapns-2-sur-3/" title="Crer un composant Apache Camel de connexion  lAPNS  2 sur 3" >Créer un composant Apache Camel de connexion à l&#8217;APNS &#8211; 2 sur 3</a></li></ul><style type="text/css">table.tablo { border-collapse:collapse; border: 1px solid #6C626C; width:95%; font: normal normal normal 1.1em/normal Arial, sans-serif; } table.tablo thead { background: #EFEFEF; border-bottom: 1px solid #6C626C; border-top: 1px solid #6C626C; color: #4F2F4F; } table.tablo thead th { padding: 5px; } table.tablo tbody tr { border: 1px solid #6C626C; } table.tablo tbody tr td { padding: 5px; }</style><div
class="shr-publisher-5625"></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div><div
class='shareaholic-like-buttonset' style='float:none;height:30px;'><a
class='shareaholic-googleplusone' data-shr_size='medium' data-shr_count='true' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2010%2F10%2F13%2Fcreer-un-composant-apache-camel-de-connexion-a-lapns-3-sur-3%2F' data-shr_title='Cr%C3%A9er+un+composant+Apache+Camel+de+connexion+%C3%A0+l%E2%80%99APNS+%E2%80%93+3+sur+3'></a><a
class='shareaholic-tweetbutton' data-shr_count='horizontal' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2010%2F10%2F13%2Fcreer-un-composant-apache-camel-de-connexion-a-lapns-3-sur-3%2F' data-shr_title='Cr%C3%A9er+un+composant+Apache+Camel+de+connexion+%C3%A0+l%E2%80%99APNS+%E2%80%93+3+sur+3'></a></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div>]]></content:encoded> <wfw:commentRss>http://blog.xebia.fr/2010/10/13/creer-un-composant-apache-camel-de-connexion-a-lapns-3-sur-3/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Créer un composant Apache Camel de connexion à l’APNS – 2 sur 3</title><link>http://blog.xebia.fr/2010/10/06/creer-un-composant-apache-camel-de-connexion-a-lapns-2-sur-3/</link> <comments>http://blog.xebia.fr/2010/10/06/creer-un-composant-apache-camel-de-connexion-a-lapns-2-sur-3/#comments</comments> <pubDate>Wed, 06 Oct 2010 20:44:21 +0000</pubDate> <dc:creator>Alexis Kinsella</dc:creator> <category><![CDATA[Java / JEE]]></category> <category><![CDATA[SOA]]></category> <category><![CDATA[Apple]]></category> <category><![CDATA[Camel]]></category> <guid
isPermaLink="false">http://blog.xebia.fr/?p=5549</guid> <description><![CDATA[Nous avons vu dans un premier article comment initier le développement d&#8217;un composant Apache Camel. Cependant, nous n&#8217;avons pas encore abordé son développement à proprement parler et notre composant ne permet pas encore de communiquer avec les serveurs Apple. Nous allons donc voir dans cet article comment implémenter les différentes classes nécessaires au bon fonctionnement [...]]]></description> <content:encoded><![CDATA[<p>Nous avons vu dans un <a
href="http://blog.xebia.fr/2010/09/30/creer-un-composant-apache-camel-de-connexion-a-lapns-1-sur-3/" title="premier article" >premier article</a> comment initier le développement d&#8217;un composant Apache Camel. Cependant, nous n&#8217;avons pas encore abordé son développement à proprement parler et notre composant ne permet pas encore de communiquer avec les serveurs Apple. Nous allons donc voir dans cet article comment implémenter les différentes classes nécessaires au bon fonctionnement de notre composant.<br
/> Pour rappel l&#8217;objectif est de développer un composant capable de communiquer avec l&#8217;Apple Push Notification Service, qui permet d&#8217;envoyer des notifications aux appareils mobiles d&#8217;Apple (iPad, iPhone, iPod Touch).</p><h3><a
name="Implmentationducomposant"></a>Implémentation du composant</h3><p>Les quatre interfaces suivantes doivent être implémentées pour développer un composant Camel permettant à la fois de consommer et produire des messages :</p><table
class="tablo"><thead><th
nowrap="true"> Interfaces à implémenter</th><th> Description</th></thead><tbody><tr><td> Component</td><td> Elle permet de créer les endpoints relatifs au composant.</td></tr><tr><td> Endpoint</td><td> Elle permet la création des <em>Consumers</em> et <em>Producers</em> relatifs à un endpoint défini par son URI.</td></tr><tr><td> Consumer</td><td> Elle correspond à l&#8217;implémentation des <em>Consumers</em> relatifs au endpoint d&#8217;un composant.</td></tr><tr><td> Producer</td><td> Elle correspond à l&#8217;implémentation des <em>Producers</em> relatifs au endpoint d&#8217;un composant.</td></tr></tbody></table><h4><a
name="LaclasseApnsService"></a>La classe ApnsService</h4><p>Pour communiquer avec les serveurs Apple, nous devons instancier un objet <em>ApnsService</em>. Le framework java-apns fournit pour cela la classe <em>ApnsServiceBuilder</em>. Celle-ci permet de construire facilement un objet <em>ApnsService</em> en spécifiant au builder la configuration souhaitée.</p><p>Le builder est obtenu grâce à la classe utilitaire <em>Apns</em> :</p><pre class="brush: java; title: ; notranslate">
        ApnsServiceBuilder builder = APNS.newService();
</pre><p>Ensuite, il suffit d&#8217;appeler les différentes méthodes de configuration du builder. Dans le cadre d&#8217;une configuration simple, le code source suivant est suffisant :</p><pre class="brush: java; title: ; notranslate">
// Instanciation du builder
ApnsServiceBuilder builder = APNS.newService();
InputStream certificateInputStream = null;
try {
    // Ouverture de l'inputStream correspondant au certificat
	certificateInputStream = ResourceUtils.getInputStream(&quot;certificate_classpath&quot;);
	// Configuration du certificat utilisé pour communiquer avec l'APNS
	builder.withCert(certificateInputStream, &quot;certificate_password&quot;)
}
finally {
	// Fermeture de l'inputStream correspondant au certificat
	ResourceUtils.close(certificateInputStream);
}
// Configuration des URLs par défaut de production vers les serveurs APNS
builder.withProductionDestination();
// Configuration d'un pool de 5 connexions vers les serveurs APNS
builder.asPool(5);
// Configuration d'une politique de reconnexion uniquement lorsqu'une connexion vers les serveurs APNS est fermée
builder.withReconnectPolicy(ReconnectPolicy.Provided.NEVER);
// Obtention de l'instance configurée
ApnsService apnsService = builder.build();
</pre><p><em>Note :</em> Un exemple de configuration plus complet de l&#8217;objet <em>ApnsService</em> peut être trouvé dans le code source du composant <em>camel-apns</em>.</p><p>Afin d&#8217;intégrer de façon efficace notre composant avec Spring, la classe <em>ApnsServiceBuilder</em> se révèle être un bon point de départ pour écrire une factory permettant de construire un objet <em>ApnsService</em> via Spring.</p><h4><a
name="LaclasseApnsComponent"></a>La classe ApnsComponent</h4><p>L&#8217;interface <em>Component</em> correspond à l&#8217;unité de base définissant un composant Camel. Ce dernier est associé au scheme d&#8217;une URI lorsqu&#8217;il est ajouté à un contexte d&#8217;exécution.</p><p>Une implémentation par défaut de cette interface est fournie (en l&#8217;occurrence la classe <em>DefaultComponent</em>), ce qui permet de se focaliser sur les fonctionnalités de notre composant. Un composant Camel a pour rôle de créer les endpoints relatifs aux URI définies dans le contexte Camel. Cette tâche est réalisée par la méthode <em>createEndpoint</em>.</p><p>Chaque endpoint créé à partir d&#8217;un même <em>ApnsComponent</em> utilisera une unique configuration pour échanger avec l&#8217;APNS. C&#8217;est pourquoi le service d&#8217;accès à l&#8217;APNS sera injecté au niveau de l&#8217;objet <em>ApnsComponent</em>.</p><p>Le bean <em>apnsService</em> peut être setté par le constructeur ou bien par un setter pour faciliter l&#8217;intégration avec Spring.</p><pre class="brush: java; title: ; notranslate">
public class ApnsComponent extends DefaultComponent {
	private ApnsService apnsService;
	public ApnsComponent() {
		super();
	}
	public ApnsComponent(ApnsService apnsService) {
		super();
		AssertUtils.notNull(apnsService, &quot;apnsService is mandatory&quot;);
		this.apnsService = apnsService;
	}
	public ApnsComponent(CamelContext context) {
		super(context);
	}
	public ApnsService getApnsService() {
		return apnsService;
	}
	@SuppressWarnings(&quot;unchecked&quot;)
	protected Endpoint createEndpoint(String uri, String remaining, Map parameters) throws Exception {
		ApnsEndpoint endpoint = new ApnsEndpoint(uri, this);
		setProperties(endpoint, parameters);
		return endpoint;
	}
    /**
     * L'objet ApnsService peut être setté s'il le constructeur vide a été appelé pour instancier un objet ApnsComponent
     */
	public void setApnsService(ApnsService apnsService) {
		if (this.apnsService != null) {
			throw new IllegalArgumentException(&quot;apnsService already setted&quot;);
		}
		this.apnsService = apnsService;
	}
}
</pre><h4><a
name="LaclasseApnsEndpoint"></a>La classe ApnsEndpoint</h4><p>La classe <em>ApnsEndpoint</em> permet de gérer la création des objets <em>Consumer</em> et <em>Producer</em> définis dans les routes Camel. Dans notre cas, nous étendrons la classe <em>ScheduledPollEndpoint</em>. Elle permet d&#8217;implémenter un endpoint qui saura créer des objets Consumer dont le déclenchement s&#8217;effectuera à intervalle régulier.</p><p>C&#8217;est la classe <em>ApnsEndpoint</em> qui a la charge de gérer les paramètres passés dans l&#8217;URI. Ainsi, les tokens passés en paramètres de l&#8217;URI d&#8217;un objet <em>ApnsEndpoint</em> seront injectés automatiquement via les setters correspondant aux paramètres renseignés. Si un paramètre ne correspond pas à un setter déclaré, une exception sera alors lancée.</p><p>Afin de faciliter le travail de configuration des paramètres spécifiques au travail de polling, c&#8217;est la classe <em>ScheduledPollEndpoint</em> qui lira automatiquement les paramètres de déclenchement renseignés sur l&#8217;URI. L&#8217;<em>ApnsEndpoint</em> aura donc toutes les informations nécessaires pour configurer les paramètres de déclenchement de l&#8217;objet <em>ApnsConsumer</em>.</p><p>Dans le cas de l&#8217;exécution de tests, les paramètres de déclenchement de la consommation de messages en provenance de l&#8217;APNS peuvent être configurés de la façon suivante :</p><pre class="brush: java; title: ; notranslate">
from(&quot;apns:consumer?initialDelay=500&amp;delay=500&amp;timeUnit=MILLISECONDS&quot;)
	.to(&quot;log:com.apache.camel.component.apns?showAll=true&amp;multiline=true&quot;)
	.to(&quot;mock:result&quot;);
</pre><p>L&#8217;implémentation de la classe ApnsEndpoint donnera le code source suivant :</p><pre class="brush: java; title: ; notranslate">
public class ApnsEndpoint extends ScheduledPollEndpoint {
	@SuppressWarnings(&quot;unused&quot;)
	private static final Log LOG = LogFactory.getLog(ApnsEndpoint.class);
	private CopyOnWriteArraySet&lt;DefaultConsumer&gt; consumers = new CopyOnWriteArraySet&lt;DefaultConsumer&gt;();
	private String tokens;
	public ApnsEndpoint(String uri, ApnsComponent component) {
		super(uri, component);
	}
	public String getTokens() {
		return tokens;
	}
	public void setTokens(String tokens) {
		this.tokens = tokens;
	}
	private ApnsComponent getApnsComponent() {
		return (ApnsComponent)getComponent();
	}
    /**
     * On obtient une instance de la clase ApnsService depuis l'object ApnsComponant
     */
	public ApnsService getApnsService() {
		return getApnsComponent().getApnsService();
	}
    /**
      * Indique que le endpoint n'est instancié qu'une seule fois par le contexte Camel
      */
	public boolean isSingleton() {
		return true;
	}
    /**
     * Permet d'obtenir la liste des consumers
     */
	protected Set&lt;DefaultConsumer&gt; getConsumers() {
		return consumers;
	}
    /**
     * Permet de créer un consumer
     */
	public Consumer createConsumer(Processor processor) throws Exception {
		ApnsConsumer apnsConsumer = new ApnsConsumer(this, processor);
		configureConsumer(apnsConsumer);
		return apnsConsumer;
	}
	/**
	 * Permet de créer un producer
	 */
	public Producer createProducer() throws Exception {
		return new ApnsProducer(this);
	}
}
</pre><h4><a
name="LaclasseApnsProducer"></a>La classe ApnsProducer</h4><p>La classe <em>ApnsProducer</em> correspond à la classe qui permet d&#8217;envoyer des notifications aux terminaux mobiles Apple via les serveurs APNS. La classe abstraite <em>DefaultProducer</em> sera étendue pour fournir un support de base à notre implémentation.</p><p>Seule la méthode <em>process</em> reste ainsi à renseigner. Il suffira d&#8217;y implémenter l&#8217;envoi de la notification à l&#8217;APNS comme suit :</p><pre class="brush: java; title: ; notranslate">
public class ApnsProducer extends DefaultProducer {
	private static final transient Log LOG = LogFactory.getLog(ApnsProducer.class);
	private ApnsEndpoint endpoint;
	private List&lt;String&gt; tokenList;
	public ApnsProducer(ApnsEndpoint endpoint) {
		super(endpoint);
		this.endpoint = endpoint;
		configureTokens(apnsEndpoint);
	}
    /**
     * La méthode configureTokens permet d'extraire la liste de tokens destinataires
     * des notifications envoyées au endpoint.
     */
	private void configureTokens(ApnsEndpoint apnsEndpoint) {
		if (StringUtils.isNotEmpty(apnsEndpoint.getTokens())) {
			try {
				this.tokenList = extractTokensFromString(apnsEndpoint.getTokens());
			} catch (CamelException e) {
				throw new IllegalArgumentException(e);
			}
		}
	}
	/**
	 * Méthode appelée par le producer pour traiter les échanges Camel
	 */
	public void process(Exchange exchange) throws Exception {
		notify(exchange);
	}
	/**
	 * La méthode notify  est appelée pour envoyer une notification aux serveurs APNS.
	 */
	private void notify(Exchange exchange) throws ApnsException, CamelException {
		String payload = exchange.getIn().getBody(String.class);
                // Une copie de la liste des tokens à notifier est passée en paramètre,
                // ainsi que le payload du message
		endpoint.getApnsService().push(new ArrayList&lt;String&gt;(tokenList), payload);
	}
	/**
	 * On extrait une liste de tokens à partir d'une chaîne de caractères contenant
	 * des tokens séparés par un point virgule.
	 */
	private List&lt;String&gt; extractTokensFromString(String tokensStr) throws CamelException {
		tokensStr = StringUtils.trim(tokensStr);
		if (tokensStr.isEmpty()) {
			throw new CamelException(&quot;No token specified&quot;);
		}
		String[] tokenArray = tokensStr.split(&quot;;&quot;);
		int tokenArrayLength = tokenArray.length;
		for (String token : tokenArray) {
			token = token.trim();
			int tokenLength = token.length();
			// La taille d'un token est limitée à 64 caractères
			if (tokenLength != 64) {
				throw new CamelException(&quot;Token has wrong size['&quot; + tokenLength + &quot;']: &quot; + token);
			}
		}
		List&lt;String&gt; tokens = Arrays.asList(tokenArray);
		return tokens;
	}
}
</pre><p>Une fois la notification envoyée aux serveurs APNS, le terminal Apple recevra la notification et l&#8217;affichera comme suit dans le cas d&#8217;une notification texte:</p><div
style="text-align: center;"><img
src="http://blog.xebia.fr/wp-content/uploads/2010/10/iphone-push-notification-1st-screenshots.jpg" alt="iphone-push-notification-1st-screenshots" title="iphone-push-notification-1st-screenshots" width="243" height="366" class="aligncenter size-full wp-image-5574" />&nbsp;&nbsp;<img
src="http://blog.xebia.fr/wp-content/uploads/2010/10/iphone-push-notification-2nd-screenshots1.jpg" alt="iphone-push-notification-2nd-screenshots" title="iphone-push-notification-2nd-screenshots" width="243" height="366" class="aligncenter size-full wp-image-5578" /></div><h4><a
name="LaclasseApnsConsumer"></a>La classe ApnsConsumer</h4><p>La classe <em>ApnsConsumer</em> a pour objectif de nous permettre de consommer le flux feedback renvoyé par les serveurs APNS, permettant de connaître les terminaux mobiles Apple pour lesquels il n&#8217;est plus nécessaire d&#8217;envoyer de notifications (Par exemple, lorsque l&#8217;application a été désintallée).</p><p>Comme vu précédemment, la stratégie de consommation peut suivre un pattern de type <a
href="http://camel.apache.org/event-driven-consumer.html" title="Event Driven Consumer" >Event Driven Consumer</a> ou bien de <a
href="http://camel.apache.org/polling-consumer.html" title="Polling Consumer" >Polling Consumer</a>. Ici, nous choisirons le pattern Event Driven Consumer, et nous étendrons la classe <em>ScheduledPollConsumer</em> qui prend en charge toute la complexité de la gestion de consommation des messages et nous laisse nous concentrer sur le principal, c&#8217;est à dire, fournir les messages à consommer par nos routes de traitement.</p><p>Pour cela, il suffit d&#8217;implémenter la méthode <em>poll</em> qui permet d&#8217;interroger le service feedback d&#8217;Apple selon le timing d&#8217;interrogation configuré par l&#8217;URI.</p><p>C&#8217;est la classe <em>ApnsEndpoint</em>, qui au moment de la création de l&#8217;objet <em>ApnsConsumer</em>, configurera les paramétrages de polling à partir des paramètres récupérés via l&#8217;URI.</p><p>La méthode <em>doStart</em> aura pour rôle de vérifier qu&#8217;un seul objet <em>ApnsConsumer</em> est créé afin de ne pas consommer en double les messages d&#8217;une même configuration de l&#8217;<em>ApnsService</em>.</p><p>La méthode <em>poll</em> est implémentée ici de façon à récupérer les informations sur les appareils pour lesquels il ne faut plus envoyer de notifications. Pour cela, nous récupérons dans un premier temps une liste d&#8217;objets <em>InactiveDevice</em> renvoyés par le flux feedback de l&#8217;APNS, puis nous itérons sur cette liste pour les faire traiter par le processor Camel, qui n&#8217;est autre que la route de traitement Camel.</p><pre class="brush: java; title: ; notranslate">
public class ApnsConsumer extends ScheduledPollConsumer {
	private static final int DEFAULT_CONSUME_INITIAL_DELAY = 10;
	private static final int DEFAULT_CONSUME_DELAY = 3600;
	private static final TimeUnit DEFAULT_CONSUME_TIME_UNIT = TimeUnit.SECONDS;
	private static final boolean DEFAULT_APNS_FIXED_DELAY = true;
	/**
	 * La configuration par défaut des paramètres de polling est fait lors de la
	 * construction de l'objet. Ces valeurs pourront être écrasées par des valeurs
	 * configurées via l'URI.
	 */
	public ApnsConsumer(ApnsEndpoint apnsEndpoint, Processor processor) {
		super(apnsEndpoint, processor);
		setInitialDelay(DEFAULT_CONSUME_INITIAL_DELAY);
		setDelay(DEFAULT_CONSUME_DELAY);
		setTimeUnit(DEFAULT_CONSUME_TIME_UNIT);
		setUseFixedDelay(DEFAULT_APNS_FIXED_DELAY);
	}
	/**
	 * Chaque élément de cette liste obtenue par l'appel de la méthode  getInactiveDevices()
	 * sera passé à la route Camel via l'appel de la méthode getProcessor().process(e)
	 */
	protected void poll() throws Exception {
		List&lt;InactiveDevice&gt; inactiveDeviceList = getInactiveDevices();
		Iterator&lt;InactiveDevice&gt; it = inactiveDeviceList.iterator();
		while(it.hasNext()) {
			InactiveDevice inactiveDevice = it.next();
			Exchange e = getEndpoint().createExchange();
			e.getIn().setBody(inactiveDevice);
			// On donne chaque élément de la liste de terminaux inactifs
			// reçu sur le flux feedback pour qu'il soit traité par la route associée
			getProcessor().process(e);
		}
	}
	/**
	 * La méthode getInactiveDevices() permet d'obtenir depuis le flux feedback une
	 * liste d'objects InactiveDevice.
	 */
	private List&lt;InactiveDevice&gt; getInactiveDevices() {
		ApnsEndpoint ae = (ApnsEndpoint)getEndpoint();
		Map&lt;String, Date&gt; inactiveDeviceMap = ae.getApnsService().getInactiveDevices();
		List&lt;InactiveDevice&gt; inactiveDeviceList = new ArrayList&lt;InactiveDevice&gt;();
		for (Entry&lt;String, Date&gt; inactiveDeviceEntry : inactiveDeviceMap.entrySet()) {
			String deviceToken = inactiveDeviceEntry.getKey();
			Date date = inactiveDeviceEntry.getValue();
			InactiveDevice inactiveDevice = new InactiveDevice(deviceToken, date);
			inactiveDeviceList.add(inactiveDevice);
		}
		return inactiveDeviceList;
	}
    @Override
	public ApnsEndpoint getEndpoint() {
		return (ApnsEndpoint)super.getEndpoint();
	}
	/**
	 * La consommation du flux feedback doit être faite par un unique consumer.
	 * La méthode doStart permet de s'enassurer lors du démarrage.
	 * Si un autre consumer est déjà déclaré, alors une exception sera lancée.
	 */
    @Override
    protected void doStart() throws Exception {
        // only add as consumer if not already registered
        if (!getEndpoint().getConsumers().contains(this)) {
            if (!getEndpoint().getConsumers().isEmpty()) {
                throw new IllegalStateException(&quot;Endpoint &quot; + getEndpoint().getEndpointUri() + &quot; only allows 1 active consumer but you attempted to start a 2nd consumer.&quot;);
            }
            getEndpoint().getConsumers().add(this);
        }
        super.doStart();
    }
    @Override
    protected void doStop() throws Exception {
        super.doStop();
        getEndpoint().getConsumers().remove(this);
    }
}
</pre><h3><a
name="Conclusion"></a>Conclusion</h3><p>Nous avons vu dans cette seconde partie comment implémenter les classes nécessaires au développement d&#8217;un composant Apache Camel. Nous verrons dans une dernière partie comment mettre en place différentes stratégies de test pour valider notre composant.</p><h3><a
name="Liensutiles"></a>Liens utiles</h3><ul><li><a
href="http://camel.apache.org/writing-components.html" title="httpcamelapacheorgwritingcomponentshtml" >http://camel.apache.org/writing-components.html</a></li><li><a
href="http://soa.dzone.com/news/camel-component-amazon-sqs?mz=7893-progress" title="Cration dun composant Camel pour communiquer avec Amazon SQS" >Création d&#8217;un composant Camel pour communiquer avec Amazon SQS</a></li><li><a
href="http://developer.apple.com/library/ios/#documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/ApplePushService/ApplePushService.html" title="Apple Push Notification Service par Apple" >Apple Push Notification Service par Apple</a></li><li><a
href="http://developer.apple.com/library/ios/#documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CommunicatingWIthAPS/CommunicatingWIthAPS.html" title="Provider Communication with Apple Push Notification Service par Apple" >Provider Communication with Apple Push Notification Service par Apple</a></li></ul><p>Le site google code du composant &#8216;camel-apns&#8217; présenté dans l&#8217;article :</p><ul><li><a
href="http://code.google.com/p/camel-apns" title="httpcodegooglecompcamelapns" >http://code.google.com/p/camel-apns</a></li></ul><p>Parties suivantes et précédentes de l&#8217;article :</p><ul><li><a
href="http://blog.xebia.fr/2010/10/06/creer-un-composant-apache-camel-de-connexion-a-lapns-1-sur-3/" title="Créer un composant Apache Camel de connexion à l'APNS - 1 sur 3" >Créer un composant Apache Camel de connexion à l&#8217;APNS &#8211; 1 sur 3</a></li><li><a
href="http://blog.xebia.fr/2010/10/06/creer-un-composant-apache-camel-de-connexion-a-lapns-3-sur-3/" title="Créer un composant Apache Camel de connexion à l'APNS - 3 sur 3" >Créer un composant Apache Camel de connexion à l&#8217;APNS &#8211; 3 sur 3</a></li></ul><style type="text/css">table.tablo { border-collapse:collapse; border: 1px solid #6C626C; width:95%; font: normal normal normal 1.1em/normal Arial, sans-serif; } table.tablo thead { background: #EFEFEF; border-bottom: 1px solid #6C626C; border-top: 1px solid #6C626C; color: #4F2F4F; } table.tablo thead th { padding: 5px; } table.tablo tbody tr { border: 1px solid #6C626C; } table.tablo tbody tr td { padding: 5px; }</style><div
class="shr-publisher-5549"></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div><div
class='shareaholic-like-buttonset' style='float:none;height:30px;'><a
class='shareaholic-googleplusone' data-shr_size='medium' data-shr_count='true' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2010%2F10%2F06%2Fcreer-un-composant-apache-camel-de-connexion-a-lapns-2-sur-3%2F' data-shr_title='Cr%C3%A9er+un+composant+Apache+Camel+de+connexion+%C3%A0+l%E2%80%99APNS+%E2%80%93+2+sur+3'></a><a
class='shareaholic-tweetbutton' data-shr_count='horizontal' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2010%2F10%2F06%2Fcreer-un-composant-apache-camel-de-connexion-a-lapns-2-sur-3%2F' data-shr_title='Cr%C3%A9er+un+composant+Apache+Camel+de+connexion+%C3%A0+l%E2%80%99APNS+%E2%80%93+2+sur+3'></a></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div>]]></content:encoded> <wfw:commentRss>http://blog.xebia.fr/2010/10/06/creer-un-composant-apache-camel-de-connexion-a-lapns-2-sur-3/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Créer un composant Apache Camel de connexion à l&#8217;APNS &#8211; 1 sur 3</title><link>http://blog.xebia.fr/2010/09/30/creer-un-composant-apache-camel-de-connexion-a-lapns-1-sur-3/</link> <comments>http://blog.xebia.fr/2010/09/30/creer-un-composant-apache-camel-de-connexion-a-lapns-1-sur-3/#comments</comments> <pubDate>Thu, 30 Sep 2010 07:12:01 +0000</pubDate> <dc:creator>Alexis Kinsella</dc:creator> <category><![CDATA[Java / JEE]]></category> <category><![CDATA[SOA]]></category> <category><![CDATA[Apple]]></category> <category><![CDATA[Camel]]></category> <guid
isPermaLink="false">http://blog.xebia.fr/?p=5537</guid> <description><![CDATA[Le projet Apache Camel est un framework d&#8217;intégration basé sur l&#8217;implémentation de patterns d&#8217;intégration d&#8217;entreprise connus. Il permet d&#8217;implémenter des règles de routage et de médiation à partir d&#8217;un DSL Java ou bien via des configurations Spring au format Xml. Apache Camel utilise la notion d&#8217;URIs, ce qui permet de travailler facilement avec différents types [...]]]></description> <content:encoded><![CDATA[<p>Le projet Apache Camel est un framework d&#8217;intégration basé sur l&#8217;implémentation de patterns d&#8217;intégration d&#8217;entreprise connus. Il permet d&#8217;implémenter des règles de routage et de médiation à partir d&#8217;un DSL Java ou bien via des configurations Spring au format Xml.</p><p>Apache Camel utilise la notion d&#8217;URIs, ce qui permet de travailler facilement avec différents types de transport ou modèles d&#8217;échange de messages, tels que HTTP ou JMS. De la même manière, Apache Camel est capable de travailler avec différents formats de données (Csv, Xml, Json, &#8230;).</p><p>L&#8217;utilisation des composants fournis <em>out of the box</em> permet de travailler avec de nombreux protocoles et formats de données. Mais qu&#8217;en est-il lorsqu&#8217;un connecteur vient à manquer?</p><p>Pour répondre à cette question, le projet Apache Camel propose une API complète permettant d&#8217;implémenter soi-même des composants adaptés à son besoin.</p><h3><a
name="Objectif"></a>Objectif</h3><p>L&#8217;objectif de cet article est de présenter comment initier le développement d&#8217;un composant Apache Camel.</p><p>Pour cela, nous mettrons en place un composant qui permettra de dialoguer avec l&#8217;<em>Apple Push Notification Service</em>, dans le but d&#8217;envoyer des notifications aux différents terminaux Apple (iPad, iPhone, iPod Touch).</p><p>Le composant proposera à la fois des endpoints de type <em>producer</em> et de type <em>consumer</em> qui permettrons respectivement d&#8217;envoyer des notifications et de lire un flux feedback d&#8217;informations en provenance de l&#8217;APNS.</p><p>En pré-requis, un ensemble de endpoints devra utiliser une même instance de la classe <em>ApnsService</em> proposée par la librairie java-apns, qui permet de dialoguer avec les serveurs d&#8217;Apple. La firme à la pomme préconise en effet de créer un nombre limité de connexions, et de réutiliser celles-ci pour communiquer avec ses serveurs. Nous utiliserons également le scheme <em>apns</em> pour déclarer les URIs qui représenteront les endpoints gérés par nos composants.</p><h3><a
name="PrsentationdelAPNS"></a>Présentation de l&#8217;APNS</h3><p>L&#8217;Apple Push Notification Service est disponible pour les applications destinées aux iPhones, iPads et iPods touch. Il permet d&#8217;envoyer des notifications de 3 types : texte, image ou badge.</p><p>Pour envoyer une notification, un provider (une application serveur en général) doit en premier lieu envoyer la notification à l&#8217;Apple Push Notification Service qui se chargera à son tour de diffuser la notification aux terminaux concernés.</p><p>La notification est composée d&#8217;un token (identifiant unique d&#8217;un terminal) et d&#8217;un payload (contenu de la notification).</p><div
align="center"> <img
src="http://blog.xebia.fr/wp-content/uploads/2010/09/remote_notif_simple.jpg" border="0" alt="Simple notification APNS" /></div><p>L&#8217;APNS propose en complément de l&#8217;envoi de notifications, un flux feedback d&#8217;informations permettant de connaître la liste des terminaux pour lesquels les notifications n&#8217;ont pu être délivrées de façon répétée (généralement, lorsque l&#8217;application a été désinstallée).</p><p>Pour qu&#8217;une application iOS soit en mesure de recevoir des notifications, elle doit en premier lieu fournir à l&#8217;application serveur (celle qui va envoyer les notifications aux serveurs Apple) toutes les informations nécessaires notamment son token d&#8217;identification. Cette opération peut-être réalisée, par exemple, via un simple appel HTTP.</p><div
align="center"> <img
src="http://blog.xebia.fr/wp-content/uploads/2010/09/registration_sequence.jpg" border="0" alt="Séquence d'enregistrement" /></div><h3><a
name="APIJavadeconnexionlAPNS"></a>API Java de connexion à l&#8217;APNS</h3><p>De nombreux projets permettent de dialoguer avec l&#8217;APNS via différents langages de programmation. Actuellement deux implémentations existent pour le langage Java :</p><ul><li><a
href="http://github.com/notnoop/java-apns" title="javaapns" >java-apns</a> sur GitHub, et</li><li><a
href="http://code.google.com/p/javapns/" title="javapns" >javapns</a> sur Google Code.</li></ul><p>Historiquement, l&#8217;implémentation javapns est apparue avant java-apns. Cependant nous choisirons d&#8217;utiliser la librairie java-apns qui a pour avantage de proposer des fonctionnalités complètes (gestion de pool de connections, capacité de reconnexion, &#8230;), ainsi qu&#8217;une API élégante et différentes facilités d&#8217;écriture de tests unitaires.</p><h3><a
name="LesendpointsCamel"></a>Les endpoints Camel</h3><p>Le développement d&#8217;un endpoint Apache Camel implique d&#8217;implémenter une ou plusieurs des méthodes suivantes selon les besoins :</p><table
class="tablo" border="0"><thead><th> Méthode</th><th> Description</th></thead><tbody><tr><td> createProducer()</td><td> Crée un producer permettant d&#8217;envoyer des messages à un endpoint</td></tr><tr><td> createConsumer()</td><td> Crée un consumer implémentant le pattern Event Driven Consumer pour consommer des messages depuis un endpoint</td></tr><tr><td> createPollingConsumer()</td><td> Crée un consumer implémentant le Polling Consumer pour consommer des messages depuis un endpoint</td></tr></tbody></table><h4><a
name="LEventDrivenConsumer"></a>L&#8217;Event Driven Consumer</h4><div
align="center"> <img
src="http://blog.xebia.fr/wp-content/uploads/2010/09/event-driven-consumer-solution.gif" border="0" alt="Solution Event Driven Consumer" /></div><p>Ce modèle événementiel de consommation des messages correspond au modèle de consommation par défaut des messages par les composants Camel.</p><h4><a
name="LePollingConsumer"></a>Le Polling Consumer</h4><div
align="center"> <img
src="http://blog.xebia.fr/wp-content/uploads/2010/09/polling-consumer-solution.gif" border="0" alt="Solution Polling Consumer" /></div><p>Le polling consumer propose 3 types de méthodes:</p><table
class="tablo" border="0"><thead><th> Méthode</th><th> Description</th></thead><tbody><tr><td> receive()</td><td> Attend qu&#8217;un échange soit disponible et le retourne (potentiellement indéfiniment)</td></tr><tr><td> receive(long)</td><td> Attend un échange jusqu&#8217;à un timeout défini. Renvoie null si aucun échange n&#8217;a été reçu dans le temps imparti</td></tr><tr><td> receiveNoWait()</td><td> Tente de recevoir un message sans attendre de timeout et retourne null si aucun échange n&#8217;est disponible</td></tr></tbody></table><p>Le composant <em>camel-jms</em> implémente cette notion de polling-consumer pour s&#8217;intégrer à Apache Camel.</p><h3><a
name="Gnrerunsquelettedecomposant"></a>Générer un squelette de composant</h3><p>Partir de zéro pourrait s&#8217;avérer compliqué. Heureusement le projet Apache Camel met à disposition l&#8217;archétype Maven: <em>camel-artefact-component</em>.</p><pre class="brush: java; title: ; notranslate">
mvn archetype:create
-DarchetypeGroupId=org.apache.camel.archetypes
-DarchetypeArtifactId=camel-archetype-component
-DarchetypeVersion=2.3.0
-DgroupId=org.apache.camel
-DartifactId=camel-apns
</pre><p>L&#8217;exécution de la ligne de commande précédente va créer un squelette de composant sur lequel s&#8217;appuyer pour développer notre composant:</p><div
align="center"> <img
src="http://blog.xebia.fr/wp-content/uploads/2010/09/maven-archetype-generated-content.png" border="0" alt="Contenu généré par l'archetype Maven" /></div><p>L&#8217;archétype va générer la structure nécessaire au développement du composant Camel. Cependant il sera nécessaire de personnaliser le composant nouvellement créé pour qu&#8217;il corresponde au nommage souhaité :</p><ul><li>&#8216;META-INF/services/&lt;PACKAGE_NAME&gt;/direct&#8217; devra être renommé selon le scheme de l&#8217;URI de votre composant (Dans notre cas: &#8216;apns&#8217;).</li><li>Les différentes classes générées seront préfixées par &#8216;Apns&#8217; plutôt que &#8216;Direct&#8217;.</li></ul><p>Il est possible de supprimer les classes qui ne seraient pas utilisées dans le cas où le composant serait uniquement destiné à consommer des messages ou à bien en produire.</p><p>Après renommage, le résultat obtenu doit être le suivant :</p><div
align="center"> <img
src="http://blog.xebia.fr/wp-content/uploads/2010/09/vue-composant-apns.png" border="0" alt="Vue composant APNS" /></div><h3><a
name="ImportersoncomposantdansEclips"></a>Importer son composant dans Eclipse</h3><p>Pour cela, il est possible d&#8217;utiliser la commande suivante:</p><pre class="brush: java; title: ; notranslate">
mvn eclipse:eclipse
</pre><h3><a
name="Lefichierpomxml"></a>Le fichier pom.xml</h3><p>Il est conseillé d&#8217;hériter du projet parent <em>camel-parent</em>:</p><pre class="brush: xml; title: ; notranslate">
&lt;parent&gt;
	&lt;groupId&gt;org.apache.camel&lt;/groupId&gt;
	&lt;artifactId&gt;camel-parent&lt;/artifactId&gt;
	&lt;version&gt;2.4.0&lt;/version&gt;
&lt;/parent&gt;
</pre><p>Le composant <em>camel-parent</em> déclare en effet un certain nombre de dépendances nécessaires, ainsi que le type <em>bundle</em> qui permet d&#8217;OSGifier son composant. Ceci permettra aux utilisateurs/développeurs de le déployer dans un conteneur OSGi, tel qu&#8217;Apache ServiceMix.</p><p>Nous allons donc déclarer le packaging du composant, ainsi que différentes propriétés nécessaires à l&#8217;OSGificiation comme suit:</p><pre class="brush: xml; title: ; notranslate">
&lt;packaging&gt;bundle&lt;/packaging&gt;
...
&lt;properties&gt;
	...
	&lt;!-- OSGi bundles properties --&gt;
	&lt;camel.osgi.import.pkg&gt;&lt;strong&gt;&lt;/camel.osgi.import.pkg&gt;
	&lt;camel.osgi.private.pkg&gt;!&lt;/strong&gt;&lt;/camel.osgi.private.pkg&gt;
	&lt;camel.osgi.export&gt;${camel.osgi.export.pkg}*;version=${camel.osgi.export.version}&lt;/camel.osgi.export&gt;
	&lt;camel.osgi.export.version&gt;${project.version}&lt;/camel.osgi.export.version&gt;
	&lt;camel.osgi.import&gt;${camel.osgi.import.pkg}&lt;/camel.osgi.import&gt;
	&lt;camel.osgi.symbolic.name&gt;${groupId}.${artifactId}&lt;/camel.osgi.symbolic.name&gt;
&lt;/properties&gt;
</pre><p>Il est également nécessaire de déclarer les dépendances Camel dont nous aurons besoin, ainsi que les dépendances nécessaires à l&#8217;implémentation du composant:</p><pre class="brush: xml; title: ; notranslate">
&lt;dependencies&gt;
	...
	&lt;!-- Camel --&gt;
	&lt;dependency&gt;
		&lt;groupId&gt;org.apache.camel&lt;/groupId&gt;
		&lt;artifactId&gt;camel-core&lt;/artifactId&gt;
		&lt;version&gt;${camel.version}&lt;/version&gt;
	&lt;/dependency&gt;
	&lt;dependency&gt;
		&lt;groupId&gt;org.apache.camel&lt;/groupId&gt;
		&lt;artifactId&gt;camel-spring&lt;/artifactId&gt;
		&lt;version&gt;${camel.version}&lt;/version&gt;
	&lt;/dependency&gt;
	&lt;dependency&gt;
		&lt;groupId&gt;org.apache.camel&lt;/groupId&gt;
		&lt;artifactId&gt;camel-test&lt;/artifactId&gt;
		&lt;version&gt;${camel.version}&lt;/version&gt;
		&lt;scope&gt;test&lt;/scope&gt;
	&lt;/dependency&gt;
	...
	&lt;!-- APNS --&gt;
	&lt;dependency&gt;
		&lt;groupId&gt;com.notnoop.apns&lt;/groupId&gt;
		&lt;artifactId&gt;apns&lt;/artifactId&gt;
		&lt;version&gt;${apns.version}&lt;/version&gt;
		&lt;exclusions&gt;
			&lt;exclusion&gt;
				&lt;groupId&gt;ch.qos.logback&lt;/groupId&gt;
				&lt;artifactId&gt;logback-classic&lt;/artifactId&gt;
			&lt;/exclusion&gt;
		&lt;/exclusions&gt;
	&lt;/dependency&gt;
	...
&lt;/dependencies&gt;
</pre><p>Le projet Apache Camel propose le plugin <em>camel-maven-plugin</em> que nous allons déclarer dans notre fichier pom. Celui-ci permet de lancer en ligne de commande une instance standalone d&#8217;Apache Camel et de démarrer les routes qui sont déclarées dans le classpath via le fichier Spring suivant: &#8216;META-INF/spring/camel-context.xml&#8217;.</p><pre class="brush: xml; title: ; notranslate">
&lt;!-- allows the route to be ran via 'mvn camel:run' --&gt;
&lt;plugin&gt;
	&lt;groupId&gt;org.apache.camel&lt;/groupId&gt;
	&lt;artifactId&gt;camel-maven-plugin&lt;/artifactId&gt;
	&lt;version&gt;${camel.version}&lt;/version&gt;
&lt;/plugin&gt;
</pre><p>Plusieurs entrées <em>repository</em> et <em>pluginReposity</em> doivent également être déclarées dans le pom afin que Maven puisse importer différentes dépendances et plugins nécessaires à notre projet:</p><pre class="brush: xml; title: ; notranslate">
&lt;repositories&gt;
	&lt;repository&gt;
		&lt;id&gt;open.iona.m2&lt;/id&gt;
		&lt;name&gt;IONA Open Source Community Release Repository&lt;/name&gt;
		&lt;url&gt;http://repo.open.iona.com/maven2&lt;/url&gt;
		&lt;snapshots&gt;
			&lt;enabled&gt;false&lt;/enabled&gt;
		&lt;/snapshots&gt;
		&lt;releases&gt;
			&lt;enabled&gt;true&lt;/enabled&gt;
		&lt;/releases&gt;
	&lt;/repository&gt;
	&lt;repository&gt;
		&lt;id&gt;open.iona.m2-snapshot&lt;/id&gt;
		&lt;name&gt;IONA Open Source Community Snapshot Repository&lt;/name&gt;
		&lt;url&gt;http://repo.open.iona.com/maven2-snapshot&lt;/url&gt;
		&lt;snapshots&gt;
			&lt;enabled&gt;true&lt;/enabled&gt;
		&lt;/snapshots&gt;
		&lt;releases&gt;
			&lt;enabled&gt;false&lt;/enabled&gt;
		&lt;/releases&gt;
	&lt;/repository&gt;
	&lt;!-- java-apns repository --&gt;
	&lt;repository&gt;
		&lt;id&gt;notnoop-repos&lt;/id&gt;
		&lt;url&gt;http://notnoop.github.com/m2-repo&lt;/url&gt;
	&lt;/repository&gt;
	...
	&lt;repository&gt;
		&lt;id&gt;apache.incubating.releases&lt;/id&gt;
		&lt;name&gt;Apache Incubating Release Distribution Repository&lt;/name&gt;
		&lt;url&gt;http://people.apache.org/repo/m2-incubating-repository&lt;/url&gt;
	&lt;/repository&gt;
&lt;/repositories&gt;
&lt;pluginRepositories&gt;
	&lt;pluginRepository&gt;
		&lt;id&gt;open.iona.m2&lt;/id&gt;
		&lt;name&gt;IONA Open Source Community Release Repository&lt;/name&gt;
		&lt;url&gt;http://repo.open.iona.com/maven2&lt;/url&gt;
		&lt;snapshots&gt;
			&lt;enabled&gt;false&lt;/enabled&gt;
		&lt;/snapshots&gt;
		&lt;releases&gt;
			&lt;enabled&gt;true&lt;/enabled&gt;
		&lt;/releases&gt;
	&lt;/pluginRepository&gt;
	&lt;pluginRepository&gt;
		&lt;id&gt;open.iona.m2-snapshot&lt;/id&gt;
		&lt;name&gt;IONA Open Source Community Snapshot Repository&lt;/name&gt;
		&lt;url&gt;http://repo.open.iona.com/maven2-snapshot&lt;/url&gt;
		&lt;snapshots&gt;
			&lt;enabled&gt;true&lt;/enabled&gt;
		&lt;/snapshots&gt;
		&lt;releases&gt;
			&lt;enabled&gt;false&lt;/enabled&gt;
		&lt;/releases&gt;
	&lt;/pluginRepository&gt;
	&lt;pluginRepository&gt;
		&lt;id&gt;maven-repository.dev.java.net&lt;/id&gt;
		&lt;name&gt;Java.net Maven 2 Repository&lt;/name&gt;
		&lt;url&gt;http://download.java.net/maven/2&lt;/url&gt;
	&lt;/pluginRepository&gt;
&lt;/pluginRepositories&gt;
</pre><h3><a
name="Conclusion"></a>Conclusion</h3><p>Nous avons vu dans cette première partie comment initier le développement d&#8217;un composant Camel à l&#8217;aide de l&#8217;archétype Maven <em>camel-archetype-component</em>.</p><p>Dans un prochain billet, nous verrons comment implémenter les différentes classes d&#8217;un composant Camel. Puis nous conclurons dans une troisième et dernière partie, par la présentation des méthodes permettant de tester notre composant afin de fournir un livrable de qualité.</p><h3><a
name="Liensutiles"></a>Liens utiles:</h3><ul><li><a
href="http://camel.apache.org" title="Le site du projet Apache Camel" >Le site du projet Apache Camel</a></li><li><a
href="http://camel.apache.org/creating-a-new-camel-component.html" title="httpcamelapacheorgcreatinganewcamelcomponenthtml" >http://camel.apache.org/creating-a-new-camel-component.html</a></li></ul><p>Le site google code du composant <em>camel-apns</em> présenté dans cet article:</p><ul><li><a
href="http://code.google.com/p/camel-apns" title="httpcodegooglecompcamelapns" >http://code.google.com/p/camel-apns</a></li></ul><p>Parties suivantes de l&#8217;article :</p><ul><li><a
href="http://blog.xebia.fr/2010/10/06/creer-un-composant-apache-camel-de-connexion-a-lapns-2-sur-3/" title="Créer un composant Apache Camel de connexion à l'APNS - 2 sur 3" >Créer un composant Apache Camel de connexion à l&#8217;APNS &#8211; 2 sur 3</a></li><li><a
href="http://blog.xebia.fr/2010/10/06/creer-un-composant-apache-camel-de-connexion-a-lapns-3-sur-3/" title="Créer un composant Apache Camel de connexion à l'APNS - 3 sur 3" >Créer un composant Apache Camel de connexion à l&#8217;APNS &#8211; 3 sur 3</a></li></ul><style type="text/css">table.tablo { border-collapse:collapse; border: 1px solid #6C626C; width:95%; font: normal normal normal 1.1em/normal Arial, sans-serif; } table.tablo thead { background: #EFEFEF; border-bottom: 1px solid #6C626C; border-top: 1px solid #6C626C; color: #4F2F4F; } table.tablo thead th { padding: 5px; } table.tablo tbody tr { border: 1px solid #6C626C; } table.tablo tbody tr td { padding: 5px; }</style><div
class="shr-publisher-5537"></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div><div
class='shareaholic-like-buttonset' style='float:none;height:30px;'><a
class='shareaholic-googleplusone' data-shr_size='medium' data-shr_count='true' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2010%2F09%2F30%2Fcreer-un-composant-apache-camel-de-connexion-a-lapns-1-sur-3%2F' data-shr_title='Cr%C3%A9er+un+composant+Apache+Camel+de+connexion+%C3%A0+l%27APNS+-+1+sur+3'></a><a
class='shareaholic-tweetbutton' data-shr_count='horizontal' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2010%2F09%2F30%2Fcreer-un-composant-apache-camel-de-connexion-a-lapns-1-sur-3%2F' data-shr_title='Cr%C3%A9er+un+composant+Apache+Camel+de+connexion+%C3%A0+l%27APNS+-+1+sur+3'></a></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div>]]></content:encoded> <wfw:commentRss>http://blog.xebia.fr/2010/09/30/creer-un-composant-apache-camel-de-connexion-a-lapns-1-sur-3/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Des ESBs et des nuages</title><link>http://blog.xebia.fr/2010/09/02/des-esbs-et-des-nuages/</link> <comments>http://blog.xebia.fr/2010/09/02/des-esbs-et-des-nuages/#comments</comments> <pubDate>Thu, 02 Sep 2010 09:34:37 +0000</pubDate> <dc:creator>Mohamed-Hamza Benmansour</dc:creator> <category><![CDATA[SOA]]></category> <category><![CDATA[cloud]]></category> <category><![CDATA[Cloud Computing]]></category> <category><![CDATA[ESB]]></category> <guid
isPermaLink="false">http://blog.xebia.fr/?p=5315</guid> <description><![CDATA[La vie terrestre des ESB, aura été courte. À peine compris et apprivoisés, les voilà qui s&#8217;envolent vers d&#8217;autres cieux. En effet, depuis quelque temps, on commence à percevoir les premières initiatives d&#8217;ESB dans les nuages comme celle de la firme WSO2 avec sa plateforme Stratos ou encore celle de Savoir technologies, dans le milieu [...]]]></description> <content:encoded><![CDATA[<p>La vie terrestre des ESB, aura été courte. À peine compris et apprivoisés, les voilà qui s&#8217;envolent vers d&#8217;autres cieux. En effet, depuis quelque temps, on commence à percevoir les premières initiatives d&#8217;ESB dans les nuages comme celle de la firme WSO2 avec sa plateforme <a
href="http://wso2.com/cloud/stratos/" title="Stratos" >Stratos</a> ou encore celle de <a
href="http://www.savoirtech.com/web/public/home" title="Savoir technologies" >Savoir technologies</a>, dans le milieu hospitalier, où la mise en place d&#8217;un ESB dans les nuages a facilité les échanges des données des patients entre les différents départements.</p><p>Dans la suite de ce billet, nous allons essayer d&#8217;analyser cette tendance émergente en revenant brièvement sur :</p><ul><li>Ce qu&#8217;est un ESB et les besoins des systèmes en terme d&#8217;intégration.</li><li>Les plates-formes de cloud computing et leurs différents modèles.</li></ul><h3><a
name="LesESB"></a>Les ESB</h3><p>Les tentatives pour couvrir la définition et l&#8217;utilisation des ESB ont fait couler beaucoup d&#8217;encre. Revenir brièvement sur le sujet s&#8217;avère donc un exercice très difficile. Néanmoins, on pourrait le synthétiser de la sorte (pour plus d&#8217;approfondissement, n&#8217;hésitez pas à consulter notre <a
href="http://blog.xebia.fr/2007/10/16/livre-blanc-comprendre-et-savoir-utiliser-un-esb-dans-une-soa/" title="livre blanc" >livre blanc</a> sur le sujet) :</p><p>Un ESB est une plate-forme d&#8217;intégration basée sur des standards ouverts.  Elle combine les fonctions d&#8217;échange de messages, de transformation, de routage et d&#8217;exposition de services, afin de permettre de relier efficacement et de coordonner les différentes composantes d&#8217;un système d&#8217;information étendu. À bien des égards, un ESB pourrait être un point de départ pour l&#8217;émergence d&#8217;une SOA orientée événement ou &laquo;&nbsp;Event-Driven SOA&nbsp;&raquo;.</p><p>Quelles motivations pourraient pousser une telle plate-forme à migrer vers les nuages ? Essayons de les appréhender en s&#8217;intéressant de plus près à ce nouvel environnement d&#8217;exécution.</p><h3><a
name="Lecloudcomputing"></a>Le cloud computing</h3><p><a
href="http://fr.wikipedia.org/wiki/Cloud_computing" title="Wikipedia" >Wikipedia</a> définit le cloud computing, selon le <a
href="http://www.syntec-informatique.fr/content/download/716911/10898717/file/SYNTEC-livre%20blanc-cloud_computing_HD.pdf" title="livre blanc" >livre blanc</a> de notre cher SYNTEC, comme un concept se déclinant sous trois formes :</p><ul><li>IaaS : infrastructure as a Service. C&#8217;est le niveau le plus bas. Le fournisseur assure dans ce cas les infrastructures matérielles nécessaires à la demande et selon les besoins de scalabilité et de stockage de l&#8217;application. Le client doit prendre en charge tous les aspects OS, pile logicielle et configuration pour tirer profit de l&#8217;élasticité des infrastructures fournies. On pourra citer comme exemple <a
href="http://aws.amazon.com/ec2/" title="Amazon EC2" >Amazon EC2</a>.</li><li>PaaS : plate-forme as a Service, niveau intermédiaire. Le fournisseur met à disposition une pile logicielle spécifique à ses infrastructures matérielles. Il assure derrière la disponibilité de votre application en lui allouant dynamiquement les ressources nécessaires selon les variations de sa charge. Un des exemples les plus célèbres est <a
href="http://code.google.com/appengine/" title="Google App Engine" >Google App Engine</a></li><li>SaaS : Software as a Service, niveau le plus haut du concept. Le client consomme le logiciel hébergé par la plate-forme sur une base de paiement par utilisation (pay per use). <a
href="http://www.salesforce.com/fr/" title="SalesForce" >SalesForce</a> a été un des pionniers de ce type de service.</li></ul><p>Notons que le principe du &laquo;&nbsp;pay per use&nbsp;&raquo; s&#8217;applique aux différentes déclinaisons citées ci-dessus. Il représente un des avantages principaux du cloud computing. Il permet la rationalisation des coûts et l&#8217;élimination du gaspillage en exploitation, licences, &#8230;</p><p>Et comme  il y a toujours un &laquo;&nbsp;Mais&nbsp;&raquo;, celui du cloud computing a toujours été la sécurité des données et dans une moindre mesure le lock-in par rapport aux fournisseurs. Ce qui  a donné naissance à une nouvelle variante, les clouds privés. Les entreprises désireuses de tirer profit du concept et ne voulant pas confier leurs données stratégiques à Amazon, Google et consorts, ont opté pour cette alternative. Elles gardent ainsi la main sur l&#8217;exploitation et la gouvernance de leurs infrastructures existantes tout en les mutualisant entre leurs différentes filiales.</p><p>Les premières applications à avoir été mises dans les nuages ont été les commodités telles que les solutions de stockage, les CRM, quelques modules d&#8217;ERP (par exemple l&#8217;offre Business ByDesign de SAP)&#8230;</p><h3><a
name="QuelsargumentspourlesESBdansle"></a>Quels arguments pour les ESB dans les nuages ?</h3><p>À la suite de ce bref tour d&#8217;horizon, deux arguments semblent se dégager en faveur d&#8217;un déploiement des ESB dans le cloud :</p><ol><li>Les ESB, de par leur adoption de standards ouverts, pourraient être un jour considérés comme des commodités, ce qui en fait un bon candidat pour le cloud. Cependant, les tentatives de standardisation, telles que JBI, n&#8217;ont à ce jour pas rassemblé un nombre critique d&#8217;acteurs et l&#8217;offre actuelle du marché reste composée de solutions hétérogènes, adoptant des architectures différentes.</li><li>Un déploiement dans les nuages permettrait une intégration pervasive inter-SI, rendant les échanges entre les départements d&#8217;une même entreprise plus directs. Cela permet aussi de faciliter l&#8217;intégration des éventuelles nouvelles applications en mode SaaS avec le reste du parc applicatif.</li></ol><p>Par ailleurs, porter son bus dans les nuages induira des défis différents selon si l&#8217;on choisit un cloud privé ou public. Dans le premier cas, ils seront plutôt du côté de l&#8217;exploitation traditionnellement orientée vers la gestion des bases de données, des serveurs d&#8217;applications et des serveurs web et il faudra donc se munir d&#8217;un framework approprié pour la gestion d&#8217;ESB dans son cloud privé tel que Stratos. Dans le deuxième cas,  ils seront plus nombreux. On citera principalement, la sécurité, la gouvernance et l&#8217;ouverture des firewall afin de pouvoir communiquer avec une plate-forme publique externe.</p><h3><a
name="Perspectives"></a>Perspectives</h3><p>Les ESB dans les nuages ne sont qu&#8217;à leur début et la pertinence de ce portage est loin encore de faire l&#8217;unanimité. Certaines parties affirment même que les ESB n&#8217;ont pas leur place dans le cloud. Le débat promet d&#8217;être intéressant et animé.</p><h3><a
name="Rfrences"></a>Références</h3><ul><li><a
href="http://www.amazon.fr/syst%C3%A8me-dinformation-durable-refonte-progressive/dp/2746218291" title="Le systme dinformation durable" >Le système d&#8217;information durable</a></li><li><a
href="http://oreilly.com/catalog/9780596006754" title="Entreprise service bus" >Entreprise service bus</a></li><li><a
href="http://searchsoa.techtarget.com/news/article/0,289142,sid26_gci1514427_mem1,00.html" title="ESBs in the cloud Tricky in the early going" >ESBs in the cloud: Tricky in the early going</a></li><li><a
href="http://www.ebizq.net/blogs/soainaction/2010/06/whats_next_for_the_esb_end_of.php" title="What's Next for the ESB? End of the Line, or Cloud Broker" >What&#8217;s Next for the ESB? End of the Line, or Cloud Broker</a></li><li><a
href="http://www.runmyprocess.com/fr/content/integration-saas" title="RunMyProcess" >RunMyProcess</a></li></ul><div
class="shr-publisher-5315"></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div><div
class='shareaholic-like-buttonset' style='float:none;height:30px;'><a
class='shareaholic-googleplusone' data-shr_size='medium' data-shr_count='true' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2010%2F09%2F02%2Fdes-esbs-et-des-nuages%2F' data-shr_title='Des+ESBs+et+des+nuages'></a><a
class='shareaholic-tweetbutton' data-shr_count='horizontal' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2010%2F09%2F02%2Fdes-esbs-et-des-nuages%2F' data-shr_title='Des+ESBs+et+des+nuages'></a></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div>]]></content:encoded> <wfw:commentRss>http://blog.xebia.fr/2010/09/02/des-esbs-et-des-nuages/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>REST : Richardson Maturity Model</title><link>http://blog.xebia.fr/2010/06/25/rest-richardson-maturity-model/</link> <comments>http://blog.xebia.fr/2010/06/25/rest-richardson-maturity-model/#comments</comments> <pubDate>Fri, 25 Jun 2010 07:13:14 +0000</pubDate> <dc:creator>Christophe Heubès</dc:creator> <category><![CDATA[SOA]]></category> <category><![CDATA[REST]]></category> <category><![CDATA[RESTFul]]></category> <guid
isPermaLink="false">http://blog.xebia.fr/?p=4965</guid> <description><![CDATA[Le modèle de maturité de Richardson (Richardson Maturity Model) est un modèle qui décompose l&#8217;approche REST en trois étapes qui introduisent progressivement les principaux éléments de REST (Ressources ; Verbes et Codes retours HTTP ; Contrôles hypermédia) pour passer d&#8217;un modèle RPC sur HTTP à un modèle RESTFul. Ce modèle a été développé par Léonard [...]]]></description> <content:encoded><![CDATA[<p>Le modèle de maturité de Richardson <em>(Richardson Maturity Model)</em> est un modèle qui décompose l&#8217;approche REST en trois étapes qui introduisent progressivement les principaux éléments de REST <em>(Ressources ; Verbes et Codes retours HTTP ; Contrôles hypermédia)</em> pour passer d&#8217;un modèle RPC sur HTTP à un modèle RESTFul.</p><p>Ce modèle a été développé par <a
href="http://www.crummy.com/" title="Léonard Richardson" >Léonard Richardson</a>. Léonard Richardson est, entre autres, co-auteur du <a
href="http://www.amazon.com/gp/product/0596529260" title="livre Restful Web Service publi chez OReilly" >livre &laquo;&nbsp;Restful Web Service&nbsp;&raquo; publié chez O&#8217;Reilly</a>.<br
/> <a
href="http://martinfowler.com/" title="Martin Fowler" >Martin Fowler</a> a récemment publié un papier à propos du Modèle de Maturité de Richardson intitulé <a
href="http://martinfowler.com/articles/richardsonMaturityModel.html" title="Richardson Maturity Model steps toward the glory of REST" >&laquo;&nbsp;Richardson Maturity Model: steps toward the glory of REST&nbsp;&raquo;</a>. Dans ce papier, Martin Fowler déroule et commente le Richardson Maturity Model au travers d&#8217;un cas d&#8217;utilisation simple <em>(réserver un rendez-vous chez le médecin)</em>.</p><p>Ce billet présente le Richardson Maturity Model en s&#8217;appuyant en grande partie sur le papier de Martin Fowler. Au programme :</p><ul><li><a
href="http://blog.xebia.fr/2010/06/25/rest-richardson-maturity-model/#LeniveauLeRPCsurHTTPenPOX">Le niveau 0 : Le RPC sur HTTP en POX <em>(Plain Old XML)</em></a>.</li><li><a
href="http://blog.xebia.fr/2010/06/25/rest-richardson-maturity-model/#Leniveaulutilisationderessourc">Le niveau 1 : L&#8217;utilisation de ressources différentiées</a>.</li><li><a
href="http://blog.xebia.fr/2010/06/25/rest-richardson-maturity-model/#LeniveauLutilisationdesverbese">Le niveau 2 : L&#8217;utilisation des verbes et des codes retours HTTP</a>.</li><li><a
href="http://blog.xebia.fr/2010/06/25/rest-richardson-maturity-model/#LeniveauLutilisationdescontrle">Le niveau 3 : L&#8217;utilisation des contrôles hypermédia</a>.</li></ul><h3><a
name="LeniveauLeRPCsurHTTPenPOX"></a>Le niveau 0 : Le RPC sur HTTP en POX</h3><p>A ce niveau, qui constitue le point de départ du modèle, on ne peut pas vraiment parler de REST : on se contente d&#8217;utiliser HTTP comme système de transport pour interagir à distance avec un <em>&laquo;&nbsp;service&nbsp;&raquo;</em>.<br
/> Toutes les requêtes sont envoyées vers le même endpoint <em>(la même URI)</em> : <code>/appointmentService</code>. Elles sont complètement décrites dans le flux XML envoyé. Dans l&#8217;exemple proposé par Martin Fowler, la réservation se fait de la façon suivante :</p><p>Une première requête est envoyée pour obtenir les créneaux disponibles à une date donnée :</p><pre class="brush: xml; title: ; notranslate">
POST /appointmentService HTTP/1.1
[various other headers]
&lt;openSlotRequest date = &quot;2010-01-04&quot; doctor = &quot;mjones&quot;/&gt;
Le serveur retourne une liste de créneaux :
HTTP/1.1 200 OK
[various headers]
&lt;openSlotList&gt;
  &lt;slot start = &quot;1400&quot; end = &quot;1450&quot;&gt;
    &lt;doctor id = &quot;mjones&quot;/&gt;
  &lt;/slot&gt;
  &lt;slot start = &quot;1600&quot; end = &quot;1650&quot;&gt;
    &lt;doctor id = &quot;mjones&quot;/&gt;
  &lt;/slot&gt;
&lt;/openSlotList&gt;
</pre><p>Une deuxième requête est envoyée <em>(sur le même endpoint)</em> pour réserver un des créneaux de la liste :</p><pre class="brush: xml; title: ; notranslate">
POST /appointmentService HTTP/1.1
[various other headers]
&lt;appointmentRequest&gt;
  &lt;slot doctor = &quot;mjones&quot; start = &quot;1400&quot; end = &quot;1450&quot;/&gt;
  &lt;patient id = &quot;jsmith&quot;/&gt;
&lt;/appointmentRequest&gt;
</pre><p>Si la demande aboutit, le serveur retourne un rendez-vous :</p><pre class="brush: xml; title: ; notranslate">
HTTP/1.1 200 OK
[various headers]
&lt;appointment&gt;
  &lt;slot doctor = &quot;mjones&quot; start = &quot;1400&quot; end = &quot;1450&quot;/&gt;
  &lt;patient id = &quot;jsmith&quot;/&gt;
&lt;/appointment&gt;
</pre><p>Si la demande échoue, le serveur retourne un message d&#8217;erreur :</p><pre class="brush: xml; title: ; notranslate">
HTTP/1.1 200 OK
[various headers]
&lt;appointmentRequestFailure&gt;
  &lt;slot doctor = &quot;mjones&quot; start = &quot;1400&quot; end = &quot;1450&quot;/&gt;
  &lt;patient id = &quot;jsmith&quot;/&gt;
  &lt;reason&gt;Slot not available&lt;/reason&gt;
&lt;/appointmentRequestFailure&gt;
</pre><p>Vous noterez l&#8217;incongruité d&#8217;une réponse <code>200 OK</code> en cas d&#8217;erreur <em>(nous y reviendrons)</em>.</p><p>Cette approche revient à mettre en place un simple système RPC <em>(Remote Procédure Call)</em>. Elle met en œuvre les mêmes mécanismes que SOAP ou XML-RPC, mais en s&#8217;affranchissant des enveloppes inhérentes à ces mécanismes. Les messages échangés sont du POX <em>(Plain Old XML)</em>.</p><h3><a
name="Leniveaulutilisationderessourc"></a>Le niveau 1 : l&#8217;utilisation de ressources différenciées</h3><p>Dans le Richardson Maturity Model, le premier pas vers l&#8217;utilisation de REST consiste à introduire la notion de ressource. Ce qui est somme toute assez logique, puisque REST est un modèle d&#8217;architecture basé sur la manipulation de ressources <em>(tout est ressource)</em>.<br
/> Ainsi, là où au niveau 0, toutes les requêtes étaient faites vers un unique endpoint <em>(une unique URI)</em>, au niveau 1, les requêtes sont envoyées à des ressources individuelles : dans l&#8217;exemple de Martin Fowler, des médecins et des créneaux.</p><p>La première requête <em>(pour demander les créneaux disponibles)</em> se fait vers l&#8217;URI d&#8217;une ressource de type médecin :</p><pre class="brush: xml; title: ; notranslate">
POST /doctors/mjones HTTP/1.1
[various other headers]
&lt;openSlotRequest date = &quot;2010-01-04&quot;/&gt;
</pre><p>La requête étant faite sur un médecin <em>(une ressource)</em> particulier, le flux XML ne spécifie plus cette information.</p><p>La réponse du serveur est en substance la même, mais elle fournit maintenant pour chaque créneau un identifiant de ressource : chaque créneau est maintenant une ressource qui peut être requêtée individuellement :</p><pre class="brush: xml; title: ; notranslate">
HTTP/1.1 200 OK
[various headers]
&lt;openSlotList&gt;
  &lt;slot id = &quot;1234&quot; doctor = &quot;mjones&quot; start = &quot;1400&quot; end = &quot;1450&quot;/&gt;
  &lt;slot id = &quot;5678&quot; doctor = &quot;mjones&quot; start = &quot;1600&quot; end = &quot;1650&quot;/&gt;
&lt;/openSlotList&gt;
</pre><p>La requête de réservation d&#8217;un créneau se fait maintenant sur la ressource idoine :</p><pre class="brush: xml; title: ; notranslate">
POST /slots/1234 HTTP/1.1
[various other headers]
&lt;appointmentRequest&gt;
  &lt;patient id = &quot;jsmith&quot;/&gt;
&lt;/appointmentRequest&gt;
</pre><p>La réponse renvoyée par le serveur est la même qu&#8217;au niveau 0.</p><p>Au niveau 1, l&#8217;introduction des ressources nous permet de gérer la complexité de notre système <em>(de notre API de réservation)</em> par l&#8217;approche <em>&laquo;&nbsp;divide &#038; conquer&nbsp;&raquo;</em> : nous avons éclaté un service en plusieurs ressources.</p><h3><a
name="LeniveauLutilisationdesverbese"></a>Le niveau 2 : L&#8217;utilisation des verbes et des codes retours HTTP</h3><p>La deuxième étape de l&#8217;approche prônée par le Richardson Maturity Model est d&#8217;introduire l&#8217;utilisation des verbes et des codes retours HTTP. Dans REST, les ressources sont manipulées au travers d&#8217;un jeu de verbes simples. Le plus souvent les verbes HTTP pour la simple et bonne raison que la majeure partie des implémentations REST se fait sur HTTP.</p><p>L&#8217;idée est de tirer parti du protocole sur lequel nous nous appuyons. Ainsi, au niveau 2, Martin Fowler déroule son exemple de la façon suivante :</p><p>La première requête <em>(pour demander les créneaux disponibles)</em> se fait en utilisant une requête <code>GET</code> <em>(et non plus <code>POST</code>)</em> :</p><pre class="brush: xml; title: ; notranslate">
GET /doctors/mjones/slots?date=20100104&amp;status=open HTTP/1.1
Host: royalhope.nhs.uk
</pre><p>La réponse à cette requête est la même qu&#8217;au niveau 1.</p><p>Pour rappel, HTTP définit <code>GET</code> comme une opération &laquo;&nbsp;sécurisée&nbsp;&raquo; qui n&#8217;induit aucun changement d&#8217;état côté serveur. Cette particularité présente deux avantages :</p><ul><li>Les requêtes <code>GET</code> peuvent être invoquées autant de fois qu&#8217;on le souhaite dans n&#8217;importe quel ordre : la réponse à une requête sera toujours la même <em>(sauf bien sûr si l&#8217;état de la ressource a été modifié par ailleurs)</em>.</li><li>Les résultats des requêtes <code>GET</code> peuvent être mis en cache par les différents équipements intervenant dans la chaîne de routage de la requête <em>(dans un système comme celui de l&#8217;exemple déroulé par Martin Folwer, il conviendra évidement de régler correctement le &laquo;&nbsp;cache timeout&nbsp;&raquo;)</em>.</li></ul><p>La requête de réservation d&#8217;un créneau est la même qu&#8217;au niveau 1 <em>(en <code>POST</code>)</em>.</p><p>Les réponses retournées par le serveur sont les mêmes qu&#8217;au niveau 1 à l&#8217;exception du code retour utilisé :</p><ul><li>Si la demande aboutie, le serveur retourne un code <code>201 Created</code> : ce code réponse indique clairement qu&#8217;une nouvelle ressource a été créée. L&#8217;URI de cette ressource est contenue dans la réponse : <code>Location : slots/1234/appointment</code> <em>(la ressource elle-même, dans sa représentation XML, est également retournée afin d&#8217;éviter une requête supplémentaire au client)</em>. L&#8217;indication fournie par le code retour est plus riche qu&#8217;avec un simple <code>200 OK</code>.</li></ul><pre class="brush: xml; title: ; notranslate">
HTTP/1.1 201 Created
Location: slots/1234/appointment
[various headers]
&lt;appointment&gt;
  &lt;slot id = &quot;1234&quot; doctor = &quot;mjones&quot; start = &quot;1400&quot; end = &quot;1450&quot;/&gt;
  &lt;patient id = &quot;jsmith&quot;/&gt;
&lt;/appointment&gt;
</pre><ul><li>Si la demande échoue, le serveur retourne un code <code>409 Conflict</code> : ce code réponse indique clairement que la requête n&#8217;a pas aboutit en raison d&#8217;un conflit <em>(le créneau est déjà réservé)</em>. L&#8217;utilisation d&#8217;un code en <code>4XX</code> a ici beaucoup plus de sens que celle du <code>200 OK</code> qui devient fallacieuse quand on retourne une erreur.</li></ul><pre class="brush: xml; title: ; notranslate">
HTTP/1.1 409 Conflict
[various headers]
&lt;openSlotList&gt;
  &lt;slot id = &quot;5678&quot; doctor = &quot;mjones&quot; start = &quot;1600&quot; end = &quot;1650&quot;/&gt;
&lt;/openSlotList&gt;
</pre><p>Au niveau 2, l&#8217;utilisation des verbes et codes retours standards de HTTP nous permet de tirer pleinement parti du protocole sur lequel nous nous appuyons <em>(&laquo;&nbsp;By following the rules of HTTP we&#8217;re able to take advantage of that capability.&nbsp;&raquo;)</em>.<br
/> Cette approche nous permet également d&#8217;éliminer les variantes dans la façon de traiter les choses et ainsi, de gérer des cas similaires de façon semblable dans l&#8217;ensemble de notre API.</p><p>A propos de l&#8217;utilisation des standards HTTP, Martin Fowler soulève un point très intéressant. Comme il l&#8217;explique, les partisans de REST poussent à l&#8217;utilisation de l&#8217;ensemble des verbes HTTP <em>(ce qui permet de disposer d&#8217;une sémantique CRUD)</em>. Or, un argument souvent avancé est que le modèle REST a fait ses preuves à très grande échelle : internet est construit sur une architecture REST. En effet, cet argument est inattaquable quand il s&#8217;agit d&#8217;utiliser <code>POST</code> et <code>GET</code>, mais il devient beaucoup plus discutable quand on parle de l&#8217;utilisation des verbes <code>PUT</code> et <code>DELETE</code>.</p><h3><a
name="LeniveauLutilisationdescontrle"></a>Le niveau 3 : L&#8217;utilisation des contrôles hypermédia</h3><p>Le troisième et dernier niveau du Richardson Maturity Model introduit la notion de <a
href="http://en.wikipedia.org/wiki/HATEOAS" title="HATEOAS" >HATEOAS</a> <em>(Hypertext As The Engine Of Application State)</em>. Derrière cet acronyme barbare se cache un principe simple : les transitions possibles vers les états suivants sont fournies par des liens hypermédia.</p><p>Les requêtes sont les mêmes qu&#8217;au niveau 2, mais les réponses sont ici enrichies avec, pour chaque ressource, un élément <code>link</code> fournissant l&#8217;URI permettant de la manipuler.<br
/> Ainsi, dans l&#8217;exemple de Martin Fowler, la réponse à la requête de demande de créneaux libres est :</p><pre class="brush: xml; title: ; notranslate">
HTTP/1.1 200 OK
[various headers]
&lt;openSlotList&gt;
  &lt;slot id = &quot;1234&quot; doctor = &quot;mjones&quot; start = &quot;1400&quot; end = &quot;1450&quot;&gt;
     &lt;link rel = &quot;royalhope.nhs.uk/linkrels/slot/book&quot;
           uri = &quot;slots/1234&quot;/&gt;
  &lt;/slot&gt;
  &lt;slot id = &quot;5678&quot; doctor = &quot;mjones&quot; start = &quot;1600&quot; end = &quot;1650&quot;&gt;
     &lt;link rel = &quot;royalhope.nhs.uk/linkrels/slot/book&quot;
           uri = &quot;slots/5678&quot;/&gt;
  &lt;/slot&gt;
&lt;/openSlotList&gt;
</pre><p>Et la réponse à la requête de réservation d&#8217;un créneau est :</p><pre class="brush: xml; title: ; notranslate">
HTTP/1.1 201 Created
Location: slots/1234/appointment
[various headers]
&lt;appointment&gt;
  &lt;slot id = &quot;1234&quot; doctor = &quot;mjones&quot; start = &quot;1400&quot; end = &quot;1450&quot;/&gt;
  &lt;patient id = &quot;jsmith&quot;/&gt;
  &lt;link rel = &quot;royalhope.nhs.uk/linkrels/appointment/cancel&quot;
        uri = &quot;slots/1234/appointment&quot;/&gt;
  &lt;link rel = &quot;royalhope.nhs.uk/linkrels/appointment/addTest&quot;
        uri = &quot;slots/1234/appointment/tests&quot;/&gt;
  &lt;link rel = &quot;self&quot;
        uri = &quot;slots/1234/appointment&quot;/&gt;
  &lt;link rel = &quot;royalhope.nhs.uk/linkrels/appointment/changeTime&quot;
        uri = &quot;doctors/mjones/slots?date=20100104@status=open&quot;/&gt;
  &lt;link rel = &quot;royalhope.nhs.uk/linkrels/appointment/updateContactInfo&quot;
        uri = &quot;patients/jsmith/contactInfo&quot;/&gt;
  &lt;link rel = &quot;royalhope.nhs.uk/linkrels/help&quot;
        uri = &quot;help/appointment&quot;/&gt;
&lt;/appointment&gt;
</pre><p>Le premier avantage de l&#8217;utilisation des contrôles hypermédia est que les développeurs côté serveur peuvent refactorer les URI d&#8217;accès à l&#8217;API sans impacter les clients <em>(pour autant que les clients utilisent les URI fournies par les éléments <code>link</code>)</em>.</p><p>D&#8217;autre part, l&#8217;utilisation des contrôles hypermédia permet d&#8217;auto-documenter l&#8217;API REST. Même si cette approche ne suffit pas à documenter complètement l&#8217;API, elle fournit un premier niveau d&#8217;information :</p><ul><li>Elle aide les utilisateurs de l&#8217;API REST <em>(les développeurs de clients)</em> à explorer ses capacités : chaque réponse indique ce qu&#8217;il est possible de faire après en indiquant les ressources manipulables <em>(on notera que les éléments <code>link</code> ne fournissent pas d&#8217;indication sur les verbes utilisables)</em>.</li><li>Elle permet aux développeurs de l&#8217;API de communiquer sur les nouvelles fonctionnalités en ajoutant de nouveaux éléments <code>link</code> dans les réponses.</li></ul><h3><a
name="Perspectives"></a>Perspectives</h3><p>Le Richardson Maturity Model propose un fil conducteur permettant d&#8217;appréhender pas à pas les concepts sous-jacents à une approche RESTFul :</p><ul><li>Niveau 1 : Gérer la complexité de notre système via l&#8217;approche <em>&laquo;&nbsp;divide &#038; conquer&nbsp;&raquo;</em> en introduisant la notion de ressource.</li><li>Niveau 2 : Eliminer les variantes dans la façon de traiter les choses et de gérer des cas similaires de façon semblable en introduisant un jeu de verbes standards pour manipuler les ressources.</li><li>Niveau 3 : Auto-documenter le protocole et fournir un premier niveau de découvrabilité au travers de la notion de HATEOAS.</li></ul><p>Le Richardson Maturity Model fournit aussi un biais intéressant pour évaluer la &laquo;&nbsp;RESTitude&nbsp;&raquo; d&#8217;une architecture.</p><div
class="shr-publisher-4965"></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div><div
class='shareaholic-like-buttonset' style='float:none;height:30px;'><a
class='shareaholic-googleplusone' data-shr_size='medium' data-shr_count='true' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2010%2F06%2F25%2Frest-richardson-maturity-model%2F' data-shr_title='REST+%3A+Richardson+Maturity+Model'></a><a
class='shareaholic-tweetbutton' data-shr_count='horizontal' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2010%2F06%2F25%2Frest-richardson-maturity-model%2F' data-shr_title='REST+%3A+Richardson+Maturity+Model'></a></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div>]]></content:encoded> <wfw:commentRss>http://blog.xebia.fr/2010/06/25/rest-richardson-maturity-model/feed/</wfw:commentRss> <slash:comments>3</slash:comments> </item> <item><title>Catalogue Xebia Training</title><link>http://blog.xebia.fr/2010/02/24/catalogue-xebia-training/</link> <comments>http://blog.xebia.fr/2010/02/24/catalogue-xebia-training/#comments</comments> <pubDate>Wed, 24 Feb 2010 12:32:34 +0000</pubDate> <dc:creator>Xebia France</dc:creator> <category><![CDATA[Exploitation]]></category> <category><![CDATA[Java / JEE]]></category> <category><![CDATA[Méthodes agiles]]></category> <category><![CDATA[Performance]]></category> <category><![CDATA[RIA]]></category> <category><![CDATA[SOA]]></category> <category><![CDATA[eXtrem Programming]]></category> <category><![CDATA[JEE]]></category> <category><![CDATA[SCRUM]]></category> <category><![CDATA[XP]]></category> <guid
isPermaLink="false">http://blog.xebia.fr/?p=4085</guid> <description><![CDATA[Nous sommes heureux de vous proposer le nouveau catalogue de formation Xebia Traning : Le catalogue numérique. Le catalogue PDF. Xebia Training se positionne logiquement dans la continuité de Xebia, tant sur la qualité de son offre de formation technique que méthodologique (méthodes agiles), en proposant des formations haut de gamme animées uniquement par les [...]]]></description> <content:encoded><![CDATA[<p><a
href="http://flipflashpages.uniflip.com/2/26742/50371/pub/"><img
src="http://blog.xebia.fr/wp-content/uploads/2010/02/xebia-training.png" style="margin: 1em 1em 1em 1em; float: right;" /></a><br
/> Nous sommes heureux de vous proposer le nouveau <a
href="http://flipflashpages.uniflip.com/2/26742/50371/pub/">catalogue de formation Xebia Traning</a> :</p><ul><li>Le <a
href="http://flipflashpages.uniflip.com/2/26742/50371/pub/">catalogue numérique</a>.</li><li>Le <a
href="http://training.xebia.fr/wp-content/uploads/catalogue%20des%20formations%202010-xebia-training.pdf">catalogue PDF</a>.</li></ul><p><a
href="http://training.xebia.fr">Xebia Training</a> se positionne logiquement dans la continuité de Xebia, tant sur la qualité de son offre de formation technique que méthodologique (méthodes agiles), en proposant des formations haut de gamme animées uniquement par les référents de leur domaine.</p><p>Avec pour principe premier le refus de tout compromis sur la qualité du formateur et du contenu, <a
href="http://training.xebia.fr">Xebia Training</a> fait systématiquement intervenir des acteurs de références dans leurs domaines respectifs.</p><p>Nos formations, savant équilibre entre théorie et travaux pratiques, sont destinées à un large public soucieux d’acquérir les meilleures pratiques de notre industrie.</p><div
class="shr-publisher-4085"></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div><div
class='shareaholic-like-buttonset' style='float:none;height:30px;'><a
class='shareaholic-googleplusone' data-shr_size='medium' data-shr_count='true' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2010%2F02%2F24%2Fcatalogue-xebia-training%2F' data-shr_title='Catalogue+Xebia+Training+'></a><a
class='shareaholic-tweetbutton' data-shr_count='horizontal' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2010%2F02%2F24%2Fcatalogue-xebia-training%2F' data-shr_title='Catalogue+Xebia+Training+'></a></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div>]]></content:encoded> <wfw:commentRss>http://blog.xebia.fr/2010/02/24/catalogue-xebia-training/feed/</wfw:commentRss> <slash:comments>1</slash:comments> </item> <item><title>AMQP, une alternative à JMS ?</title><link>http://blog.xebia.fr/2010/02/23/amqp-une-alternative-a-jms/</link> <comments>http://blog.xebia.fr/2010/02/23/amqp-une-alternative-a-jms/#comments</comments> <pubDate>Tue, 23 Feb 2010 13:32:48 +0000</pubDate> <dc:creator>Guillaume Arnaud</dc:creator> <category><![CDATA[Java / JEE]]></category> <category><![CDATA[SOA]]></category> <category><![CDATA[AMQP]]></category> <category><![CDATA[broker]]></category> <category><![CDATA[JMS]]></category> <category><![CDATA[qpid]]></category> <category><![CDATA[rabbitmq]]></category> <guid
isPermaLink="false">http://blog.xebia.fr/?p=4067</guid> <description><![CDATA[Vous avez une application Java qui doit envoyer et recevoir des messages à droite et à gauche pour des raisons qui n&#8217;appartiennent qu&#8217;à vous&#8230; Votre premier réflexe sera sûrement de contacter votre vieil ami JMS. Pour ça, vous aurez aussi besoin d&#8217;un broker de message, mais vous n&#8217;êtes pas très riche et des outils comme [...]]]></description> <content:encoded><![CDATA[<p>Vous avez une application Java qui doit envoyer et recevoir des messages à droite et à gauche pour des raisons qui n&#8217;appartiennent qu&#8217;à vous&#8230; Votre premier réflexe sera sûrement de contacter votre vieil ami JMS. Pour ça, vous aurez aussi besoin d&#8217;un broker de message, mais vous n&#8217;êtes pas très riche et des outils comme WebSphere ou Tibco sont hors de portée&#8230; Vous aurez alors de <a
title="fortes chances" href="http://www.google.com/insights/search/#cat=31&amp;q=activemq%2Copenjms%2Cjboss%20messaging%2Cjoram&amp;cmpt=q">fortes chances</a> de vous tourner vers votre autre vieil ami ActiveMQ. Bon d&#8217;accord, l&#8217;amitié ça compte, mais par ailleurs d&#8217;autres amis (des vrais !) vous signalent qu&#8217;ils ont eu quelques problèmes de blocage de file avec ActiveMQ et qu&#8217;ils ont eu du mal à identifier ces problèmes. En plus vous avez encore d&#8217;autres amis qui aimeraient bien communiquer avec vous sur ce même broker mais leurs applications tournent en ruby et C++ qui parlent mal le JMS&#8230; C&#8217;est le moment idéal de vous présenter un nouvel ami : AMQP !</p><p>AMQP (<a
title="Advanced Message Queuing Protocol" href="http://jira.amqp.org/confluence/display/AMQP/Advanced+Message+Queuing+Protocol">Advanced Message Queuing Protocol</a>) est un protocole de messagerie créé à <a
title="l'initiative" href="http://queue.acm.org/detail.cfm?id=1255424">l&#8217;initiative</a> de la banque JP Morgan Chase pour gérer la communication entre ses différents partenaires. Le but affiché était de fournir une solution alternative aux solutions payantes et relativement chères dans le domaine du MOM (Message-Oriented Middleware) dominé largement par Websphere MQ d&#8217;IBM et RendezVous de Tibco (<a
title="93% du marché à eux deux en 2008" href="http://openenterprisenews.com/analysis/can-amqp-break-ibms-mom-monopoly-part-1.html">93% du marché à eux deux en 2008</a>). Un certain nombre de <a
title="partenaires" href="http://jira.amqp.org/confluence/display/AMQP/AMQP+Working+Group">partenaires</a> se sont fédérés autour de ce projet pour aboutir à une première <a
title="spcification" href="http://jira.amqp.org/confluence/display/AMQP/AMQP+Specification">spécification</a> en 2006. L&#8217;ambition avouée est qu&#8217;elle devienne l&#8217;équivalent du HTTP pour l&#8217;internet, ce qui explique qu&#8217;elle décrive aussi bien les différentes sémantiques liées au MOM que la partie plus bas niveau du transport de ces messages. Cette normalisation permet la multiplication des solutions clientes ou serveurs dont la compatibilité sera garantie par cette spécification. Par exemple, un broker de message écrit en Erlang comme RabbitMQ transférera de façon transparente un message d&#8217;un client ruby vers un autre client Java/JMS.</p><p>Notez bien qu&#8217;AMQP s&#8217;identifie clairement comme un protocole et non comme une API, contrairement à JMS. Donc un client Java basé sur JMS peut, moyennant des adaptations plus ou moins coûteuses, communiquer avec un broker AMQP.</p><h3><a
name="Unnouveauprotocole"></a>Un nouveau protocole</h3><p>Les spécifications AMQP sont parties de cas d&#8217;utilisation très concrets pour aboutir à des spécifications essayant d&#8217;englober un maximum de typologies. Voici quelques unes d&#8217;entre elles (<a
title="QPid" href="http://qpid.apache.org/faq.html#FAQ-WhatmessagingtopologiesaresupportedbyAMQPandQpid%253F">QPid</a> ou <a
title="RabbitMQ" href="http://www.rabbitmq.com/faq.html#scenarios">RabbitMQ</a>) :</p><div><img
src="http://blog.xebia.fr/wp-content/uploads/2010/02/topologies-amqp.png" border="0" alt="" /></div><ul><li><strong>Store-and-forward:</strong> les messages sont persistés puis récupérés par un seul client qui décidera s&#8217;il faut les supprimer.</li><li><strong>Point-to-point:</strong> une communication dédiée entre un émetteur et un receveur, éventuellement bidirectionnelle.</li><li><strong>One-to-many (ou fanout):</strong> un message est retransmis à toutes les queues d&#8217;une zone d&#8217;échange. Ceci permet de modéliser le multicast.</li><li><strong>Transaction (distribuée ou pas):</strong> l&#8217;émetteur peut englober un paquet de messages dans une transaction, ces messages ne pourront être lus que lorsque l&#8217;émetteur les aura acquittés.</li><li><strong>Publish-subscribe (pub-sub):</strong> plusieurs émetteurs postent des messages en fonction de mots clés (topics) auxquels s&#8217;abonnent plusieurs receveurs.</li><li><strong>Content-based routing:</strong> le routage des messages est déterminé selon le contenu du message ou par une fonction externe.</li><li><strong>Queued file transfer:</strong> on n&#8217;envoie plus de simples messages mais des fichiers, voire tout le contenu d&#8217;un répertoire.</li></ul><p>Ces différentes architectures se combinent bien sûr entre elles, je pense particulièrement aux transactions. Ces schémas de base un peu abstraits rejoignent des concepts ou des applications connus de tous. Un serveur de mail par exemple s&#8217;appuiera sur un &laquo;&nbsp;store-and-forward&nbsp;&raquo;, un chat sur un &laquo;&nbsp;point-to-point&nbsp;&raquo; ou un streaming de fichier sur un &laquo;&nbsp;queued file transfer&nbsp;&raquo;. Cette sémantique est un vrai plus pour la phase de conception d&#8217;un projet même si ensuite rien n&#8217;est figé dans la réalisation.</p><p>Derrière ces grands concepts se cachent des briques élémentaires très simples :</p><ul><li><strong>Queue de message (Message Queue):</strong> zone de stockage des messages (en mémoire ou sur le disque). Elle aura les propriétés privée/partagée, durable/transitoire, permanente/temporaire.</li><li><strong>Zone d&#8217;échange (Exchange):</strong> l&#8217;entité qui accepte les messages et les route vers les queues de messages. Les critères de routage peuvent se faire de plusieurs façons (inspection du contenu, du header, clés de routage&#8230;). Les zones d&#8217;échange peuvent être créées dynamiquement par les applications clientes.</li><li><strong>Zone virtuelle (Virtual Zone):</strong> ce concept est copié de celui des serveurs HTTP d&#8217;Apache. Cette zone crée un espace contenant différentes zones d&#8217;échange et de queues de message complètement étanches aux autres zones virtuelles. Donc une connexion au serveur ne pourra être associée qu&#8217;à une zone virtuelle. C&#8217;est très utile lorsqu&#8217;on veut mutualiser les ressources.</li></ul><div><img
src="http://blog.xebia.fr/wp-content/uploads/2010/02/amqp-global.png" border="0" alt="" /></div><p>Pour le routage, la zone d&#8217;échange pourra implémenter différents algorithmes :</p><ul><li><strong>Direct:</strong> la clé de routage correspond exactement à l&#8217;adresse de la queue.</li><li><strong>Topic:</strong> la clé de routage correspond à un certain pattern (une expression régulière) de l&#8217;adresse de la queue.</li><li><strong>Routage par le header:</strong> analyse une table clé/valeur pour décider vers quelle queue aller.</li><li><strong>Système :</strong> appel à un service externe.</li></ul><p>De même les queues de message peuvent avoir des typologies assez variées: durables après un redémarrage de serveur, auto-suppression si plus utilisées, dépendant d&#8217;un souscripteur, partagées par plusieurs souscripteurs, répondant à un message particulier&#8230;</p><p>La gestion des transactions et des transactions distribuées est également spécifiée. Un message envoyé à l&#8217;intérieur d&#8217;une transaction ne sera récupéré par les souscripteurs qu&#8217;à partir du moment où l&#8217;émetteur acquittera la transaction. Cependant, cette gestion peut varier selon l&#8217;implémentation des serveurs car lors d&#8217;un rollback, seules les commandes de l&#8217;émetteur sont dépilées. Certains états du serveur peuvent donc être modifiés malgré tout (par exemple la déclaration d&#8217;une nouvelle queue de message).</p><h3><a
name="Solutionsexistantes"></a>Solutions existantes :</h3><p><a
title="RabbitMQ" href="http://www.rabbitmq.com/">RabbitMQ</a> (Mozilla Public License) est sans doute le broker AMQP le plus connu. Il est basé sur le langage Erlang et ses librairies OTP, développé par Ericsson et réputé pour sa haute-disponibilité et sa tolérance aux pannes (règle des &laquo;&nbsp;<a
title="nine nines" href="http://en.wikipedia.org/wiki/Erlang_(programming_language)#History">nine nines</a>&nbsp;&raquo; : 99.9999999%  de disponibilité !). Au-delà de sa maturité, le point fort de ce produit est sa volonté de faciliter son intégration dans les systèmes existants. Par exemple, des distributions dédiées à Amazon EC2, avec intégration à EBS, sont proposées. La gestion du cluster est également très simple, en une commande on peut rattacher un broker à un autre. Toutes les zones d&#8217;échange, les queues de message ou les zones virtuelles seront alors partagées et répliquées. Côté client, une API Java est incluse dans la distribution, très simple et proche de l&#8217;API JMS. La communication avec un client JMS est possible grâce à une librairie proposée par <a
title="OpenAMQ" href="http://github.com/pieterh/openamq-jms">OpenAMQ</a>.</p><p><a
title="OpenAMQ" href="http://www.openamq.org/">OpenAMQ</a> propose lui-même un broker. Développé par iMatix, en C++, une API (WireAPI) est proposée. Sans doute plus complexe à appréhender, un effort particulier a néanmoins été apporté aux outils de développement (débogage, constructions de test&#8230;) et de monitoring (log, tuning&#8230;). Un langage XML (PAL) a été développé pour scripter des scénarios utiles pour les tests par exemple. Ou encore une console de monitoring pour serveur AMQP. Très pointu, OpenAMQ semble s&#8217;adresser à des experts confrontés à des projets soumis à de fortes contraintes. Il y a un côté un peu R&amp;D qui permet par ailleurs de jouer un rôle moteur dans la communauté. A noter également que la distribution linux vient avec une implémentation de RestMS.</p><p>Par ailleurs OpenAMQ a fait <a
title="main basse" href="http://www.imatix.com/press:fastmq-acquisition">main basse</a> sur un autre broker AMQP : <a
title="ZeroMQ" href="http://www.zeromq.org/">ZeroMQ</a>. Enfin plus précisément un broker qui implémente plusieurs protocoles dont AMQP. On est ici à la limite du sujet tant cette application s&#8217;attache moins à son intégration dans une application de gestion classique qu&#8217;à construire une bête de course aux performances affichées impressionnantes (13.4 microsecondes de latence end-to-end, 4.1 millions de messages à la seconde).</p><p>Avec <a
title="Qpid" href="http://qpid.apache.org/">Qpid</a> on revient un peu sur terre. Ce broker est incubé chez Apache et ne semble a priori rien apporter de plus que ceux cités plus haut. Il vaut malgré tout le coup de s&#8217;y intéresser pour les différents frameworks et librairies auxquels il s&#8217;intègre et en premier lieu celles d&#8217;Apache (Axis2, Camel, Synapse). Il est également intégré à la distribution de <a
title="Red Hat MRG" href="http://www.redhat.com/docs/en-US/Red_Hat_Enterprise_MRG/1.1/html/MRG_Messaging_Qpid_C++_API_Reference/">Red Hat MRG</a> et est compatible avec l&#8217;outil de visualisation et de contrôle <a
title="HermesJMS" href="http://www.hermesjms.com/confluence/display/HJMS/Home">HermesJMS</a>.</p><p>A noter également que le projet très en vue <a
title="HornetQ" href="http://community.jboss.org/wiki/HornetQTechnicalFAQ">HornetQ</a> de JBoss <a
title="prvoie" href="http://hornetq.sourceforge.net/docs/hornetq-2.0.0.GA/user-manual/en/html/messaging-concepts.html#d0e426">prévoit</a> également de supporter ce protocole dans une prochaine version.</p><h3><a
name="Perspectivesetenjeux"></a>Perspectives et enjeux</h3><h4><a
name="Unecommunaut"></a>Une communauté</h4><p>La capacité d&#8217;AMQP à s&#8217;imposer comme un standard sera liée à sa capacité à drainer une vraie communauté autour de lui. Cette communauté se divise en deux actuellement : les <a
title="membres" href="http://www.amqp.org/confluence/display/AMQP/AMQP+Working+Group+Legal+Name+List">membres</a> du groupe de travail AMQP et la communauté open source.</p><p>Les membres du groupe de standardisation sont eux-mêmes divisés en trois familles : des fournisseurs de brokers AMQP (RabbitMQ, OpenAMQ&#8230;), les clients historiques (JPMorgan, Goldman Sachs&#8230;) qui poussent ces solutions et les fournisseurs de solutions matérielles (Cisco, Solace Systems Inc., Tervela Inc. &#8230;). Ce mélange a le gros avantage de proposer d&#8217;ores et déjà des solutions implémentées et en production qui éprouvent ce standard et l&#8217;enrichissent en retour. La réalité du terrain guide largement les spécifications comme le montre leurs <a
title="Business Requirements" href="http://www.amqp.org/confluence/display/AMQP/AMQP+1-0+Business+Requirements">Business Requirements</a>.</p><p>Du côté OpenSource par contre la communauté reste encore discrète. En faisant une recherche rapide sur internet on trouve tout de même une bonne quantité de projets, plus ou moins expérimentaux :</p><ul><li><a
title="RestMS" href="http://www.restms.org/">RestMS</a> pour poster des messages directement en Rest.</li><li><a
title="amqpjs" href="http://github.com/dansimpson/amqp-js">amqp-js</a> pour poster des messages en javascript.</li><li><a
title="ici" href="http://blog.0x82.com/2009/12/28/twitter-amqp-websocket-example-no-polling">ici</a> une idée pour faire du twitter avec html5.</li><li><a
title="rplication" href="https://launchpad.net/rabbitreplication">réplication</a> en base de données.</li><li><a
title="des librairies spring" href="http://www.opencredo.com/technologies/opencredo-amq">des librairies spring</a> pour utiliser de façon transparente les brokers.</li></ul><p>Du chemin reste encore à faire, mais la diversité des projets prouve malgré tout qu&#8217;il y a une demande.</p><h4><a
name="Uneversionderfrence"></a>Une version de référence</h4><p>Pour l&#8217;instant la version 0.10 est la dernière version officielle. Mais la plupart des brokers sont en version 0.8 ou 0.9. En effet, tout le monde attend la <em>vraie</em> version de référence, la 1.0. qui devrait sortir cette année. Elle devrait apporter de gros changements : un système d&#8217;adressage inspiré des mails (queue_message@my_server), le remplacement des zones d&#8217;échanges par deux nouvelles entités (une queue d&#8217;entrée et un <em>service</em> d&#8217;échange), la suppression des Virtual Hosts (conséquence de la suppression des zones d&#8217;échanges), l&#8217;amélioration de la partie administration du broker et l&#8217;ajout de support pour les services DNS.</p><p>Ces gros changements apportent sûrement des améliorations majeures à ce protocole. Il n&#8217;y a plus qu&#8217;à espérer que la migration se fera rapidement. Il est difficile de dire aujourd&#8217;hui si les clients sur les versions 0.x pourront se connecter à cette nouvelle version de façon transparente, mais si ce n&#8217;est pas le cas, cela risque de casser la dynamique autour d&#8217;AMQP.</p><h4><a
name="Laconcurrence"></a>La concurrence</h4><p>La lutte est assez féroce dans le domaine du MOM. Si on met de côté Websphere MQ et Tibco, il existe de nombreuses solutions, parfois assez éloignées conceptuellement.</p><p>On peut s&#8217;en douter, ActiveMQ ne reste pas les bras croisés. Ils poussent entre autre une solution générique, <a
title="STOMP" href="http://stomp.codehaus.org/Home">STOMP</a>, très simple d&#8217;utilisation mais moins complète et moins performante. Ils annoncent aussi une compatibilité AMQP, sans qu&#8217;on sache très bien comment.</p><p>Jusqu&#8217;à un certain point, ce protocole rentre également <a
title="en concurrence" href="http://www.opensourcery.co.za/2009/04/19/to-amqp-or-to-xmpp-that-is-the-question/">en concurrence</a> avec XMPP, le protocole de messagerie instantanée.</p><p><a
title="MuleMQ" href="http://www.mulesoft.org/display/MQ/Home">MuleMQ</a> est apparu également sur la scène et est proposé comme broker dans la nouvelle distribution de l&#8217;ESB Mule. C&#8217;est un broker JMS fourni avec quelques outils. Le &laquo;&nbsp;tout-intégré&nbsp;&raquo; de cette solution peut être assez attirant, par contre on peut regretter que MuleSoft <a
title="sloigne" href="http://pzf.fremantle.org/2010/01/mule-no-longer-open-source-company.html">s&#8217;éloigne</a> de plus en plus de l&#8217;Open Source.</p><p>Au contraire, <a
title="HornetQ" href="http://www.jboss.org/hornetq">HornetQ</a> joue le jeu de l&#8217;Open Source et peut profiter de la grande expérience de JBoss dans ce domaine. Mais cela reste du JMS&#8230; Cela sera sûrement la solution privilégiée pour les applications tournant sur JBoss mais difficile de dire si la solution <em>out of the box</em> aura du succès.</p><p>Au final JMS est le vrai <a
title="concurrent" href="http://www.jroller.com/RickHigh/entry/amqp_versus_jms">concurrent</a> d&#8217;AMQP même si encore une fois les deux peuvent vivre ensemble. Un adaptateur JMS pour AMQP peut sembler intéressant pour des projets qui migrent vers un nouveau broker, mais il semble plus pertinent pour un nouveau projet de commencer directement dans ce nouveau standard. Par exemple l&#8217;utilisation de la librairie Java de RabbitMQ est vraiment très proche de l&#8217;API JMS et la vitesse d&#8217;apprentissage semble assez rapide pour un développeur Java.</p><p>Car un des problèmes de JMS c&#8217;est justement son manque d&#8217;interopérabilité avec d&#8217;autres langages. A cet égard il est intéressant de remarquer que Microsoft s&#8217;intéresse de près à AMQP. Depuis 2008 il participe au groupe de travail et a collaboré activement avec QPid pour la version C++ du broker. Etre agnostique vis-à-vis de l&#8217;environnement DotNet ou Java serait sûrement une carte majeure de ce standard.</p><h3><a
name="Conclusion"></a>Conclusion</h3><p>Les solutions propriétaires comme IBM et Tibco ne sont pas réellement menacées par ce nouveau concurrent car leurs solutions sont très complètes, éprouvées et ils fournissent un support sérieux qui rassure les DSI. Le défi d&#8217;AMQP est moins de concurrencer ces leaders que de promouvoir l&#8217;architecture orientée message au sein de projets de taille moyenne et/ou open-source qui n&#8217;ont pas forcément un gros budget à investir. L&#8217;adoption massive de ce modèle de conception imposerait AMQP comme le protocole référent tant sa spécification est avancée et complète.</p><div
class="shr-publisher-4067"></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div><div
class='shareaholic-like-buttonset' style='float:none;height:30px;'><a
class='shareaholic-googleplusone' data-shr_size='medium' data-shr_count='true' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2010%2F02%2F23%2Famqp-une-alternative-a-jms%2F' data-shr_title='AMQP%2C+une+alternative+%C3%A0+JMS+%3F'></a><a
class='shareaholic-tweetbutton' data-shr_count='horizontal' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2010%2F02%2F23%2Famqp-une-alternative-a-jms%2F' data-shr_title='AMQP%2C+une+alternative+%C3%A0+JMS+%3F'></a></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div>]]></content:encoded> <wfw:commentRss>http://blog.xebia.fr/2010/02/23/amqp-une-alternative-a-jms/feed/</wfw:commentRss> <slash:comments>24</slash:comments> </item> <item><title>Drools et les moteurs de règles</title><link>http://blog.xebia.fr/2010/01/08/drools-et-les-moteurs-de-regles/</link> <comments>http://blog.xebia.fr/2010/01/08/drools-et-les-moteurs-de-regles/#comments</comments> <pubDate>Fri, 08 Jan 2010 17:09:27 +0000</pubDate> <dc:creator>Nicolas Lecoz</dc:creator> <category><![CDATA[Java / JEE]]></category> <category><![CDATA[SOA]]></category> <category><![CDATA[Drools]]></category> <category><![CDATA[Flow]]></category> <category><![CDATA[Guvnor]]></category> <category><![CDATA[XKE]]></category> <guid
isPermaLink="false">http://blog.xebia.fr/?p=3730</guid> <description><![CDATA[Lorsque l&#8217;on entend parler de moteur de règles, on a souvent tendance à y associer le mot &#171;&#160;Drools&#160;&#187;. Pourquoi ce réflexe : Par habitude ? Parce que Drools est l&#8217;unique solution du marché Open Source ? Mais avant j&#8217;aimerais répondre à plusieurs questions : Qu&#8217;est ce qu&#8217;un moteur de règles ? Quand en a-t-on besoin [...]]]></description> <content:encoded><![CDATA[<p>Lorsque l&#8217;on entend parler de moteur de règles, on a souvent tendance à y associer le mot &laquo;&nbsp;Drools&nbsp;&raquo;.</p><p>Pourquoi ce réflexe :</p><ul><li>Par habitude ?</li><li>Parce que Drools est l&#8217;unique solution du marché Open Source ?</li></ul><p>Mais avant j&#8217;aimerais répondre à plusieurs questions :</p><ul><li>Qu&#8217;est ce qu&#8217;un moteur de règles ?</li><li>Quand en a-t-on besoin ?</li><li>Pourquoi en a-t-on besoin ?</li></ul><p>Ensuite on pourra présenter Drools !</p><h4><a
name="Questcequunmoteurderglesetpour"></a>Qu&#8217;est ce qu&#8217;un moteur de règles, et pourquoi ?</h4><p>Vu de l&#8217;extérieur, un moteur de règles est un système capable de définir des règles et de les appliquer à des faits. En vulgarisant, un fait est une donnée.<br
/> Un moteur de règles est la solution idéale pour les programmes contenant une logique nécessitant un nombre important de &laquo;&nbsp;if&nbsp;&raquo; (i.e. potentiellement détectable avec un outil d&#8217;analyse de la qualité du code, dans la rubrique complexité cyclomatique).</p><p>En regardant sous le capot, un moteur de règles est plus complexe. Les règles et les faits sont injectées à un moteur d&#8217;inférence. Ce moteur d&#8217;inférence cherche les règles applicables aux faits (<em>pattern matching</em>). Tout se passe en mémoire. C&#8217;est à dire que la règle a le même cycle de vie qu&#8217;une donnée. Une règle peut être chargée, déchargée ou modifiée en mémoire sans réinitialisation du moteur de règles. Ensuite, le moteur de règles optimise l&#8217;exécution de règles en les agençant de la manière la plus efficace possible (<em>agenda</em>).</p><div
align="center"> <img
src="http://blog.xebia.fr/wp-content/uploads/2010/01/moteurDeRegle.PNG" border="0" alt="drools moteur de regles" width="500"/></div><p>Un moteur de règles permet donc d&#8217;isoler le traitement (règles), des données (faits). De plus il permet par exemple de gérer des algorithmes avec de nombreuses micros règles qui changent souvent. Idéal, donc pour des algorithmes implémentant une logique commerciale, très variable suivant les demandes des équipes marketing. Voici un cas d&#8217;utilisation possible pour un site d&#8217;ecommerce de vente de fruits et légumes : un algorithme métier qui calcule le prix total d&#8217;une commande, applique des promotions suivant de nombreuses conditions sur le panier et la fiche client.</p><h4><a
name="Laprsentation"></a>La présentation</h4><p>Chez Xebia, tous les premiers jeudis de chaque mois, il y a un <a
href="http://blog.xebia.fr/2008/02/06/xebia-ouvre-ses-journees-de-partage-de-la-connaissance-xke/" title="XKE (Xebia Knowledge Exchange)" >XKE (Xebia Knowledge Exchange)</a>. C&#8217;est l&#8217;occasion pour tous les consultants de Xebia de se retrouver tous ensemble afin de partager sur divers sujets techniques ou d&#8217;architecture qui nous tiennent à coeur.</p><p>Lors du XKE de décembre, j&#8217;ai présenté une session sur les moteurs de règles et le framework <a
href="http://www.jboss.org/drools/" title="Drools (JBoss)" >Drools (JBoss)</a>.</p><p>Cette présentation aborde plusieurs points :</p><ul><li>Qu&#8217;est-ce qu&#8217;un moteur de règles ?</li><li>Drools, les alternatives et son historique.</li><li>Résumé d&#8217;un comparatif de moteur de règles.</li><li>Première règle, une règle simple !</li><li>Règles lisibles pour un humain (<a
href="http://blog.xebia.fr/2008/05/07/introduction-aux-dsl-avec-groovy/" title="DSL" >DSL</a> et Table de décision).</li><li><a
href="http://www.jboss.org/drools/drools-guvnor.html" title="Drools Guvnor" >Drools Guvnor</a> (<a
href="http://fr.wikipedia.org/wiki/Syst%C3%A8me_de_gestion_de_r%C3%A8gles_m%C3%A9tier" title="BRMSBPMS systme de gestion de rgles mtiers" >BRMS/BPMS, système de gestion de régles métiers</a>).</li><li><a
href="http://www.jboss.org/drools/drools-flow.html" title="Drools Flow" >Drools Flow</a> (Flow/WorkFlow).</li><li><a
href="http://www.jboss.org/drools/drools-fusion.html" title="Drools Fusion" >Drools Fusion</a> (<a
href="http://fr.wikipedia.org/wiki/Complex_event_processing" title="Event Processing" >Event Processing</a>).</li><li>Performance : <a
href="http://fr.wikipedia.org/wiki/Algorithme_de_Rete" title="Algorithme de Rete" >Algorithme de Rete</a></li></ul><p>La présentation fut dense. En effet, le focus a été mis sur la dernière version de Drools, la version 5, qui propose énormément de fonctionnalités. De plus, c&#8217;est un framework complexe qui demande une immersion longue &#8211; plusieurs mois &#8211; afin d&#8217;être autonome sur le produit. Certes, il propose de résoudre des problèmes non communs dans le monde du développement d&#8217;applications de gestion mais le choix d&#8217;une telle solution demande une étude approfondie en tenant compte de différents aspects :</p><ul><li>Besoin d&#8217;un moteur de règles, une solution de gestion de règles plus simple peut suffire comme par exemple le <a
href="http://blog.xebia.fr/2009/12/29/le-pattern-specification-pour-la-gestion-de-vos-regles-metier/" title="pattern Specification" >pattern Specification</a>,</li><li>Coût et temps :</li><ul><li>de formation des développeurs</li><li>pour la réalisation d&#8217;un prototype,</li></ul><li>Performance,</li><li>Processus de gestion des règles (qui va administrer et configurer les règles).</li></ul><p>Selon moi, les avantages de Drools sont :</p><ul><li>La résolution de manière efficace d&#8217;algorithmes non classiques.</li><li>La table de décision via un fichier Excel qui est très proche d&#8217;une spécification et ainsi évite une translation vers du code pas souvent agréable à maintenir.</li><li>Drools Guvnor, une application Web afin d&#8217;administrer et modifier à chaud les règles via une interface graphique.</li><li>L&#8217;intégration de Drools peut se faire seulement sur un point particulier de l&#8217;application, pour un algorithme par exemple. Cela aura pas d&#8217;impact sur le reste  de l&#8217;appplication.</li></ul><div
style="text-align:center" id="__ss_270612"> <object
style="width:700px;margin:0px" width="650" height="542"><param
name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=xke-20091203-drools-fr-100107094341-phpapp01&#038;stripped_title=drools-et-les-moteurs-de-rgles"/><param
name="allowFullScreen" value="true"/><param
name="allowScriptAccess" value="always"/><embed
src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=xke-20091203-drools-fr-100107094341-phpapp01&#038;stripped_title=drools-et-les-moteurs-de-rgles" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="650" height="542"></embed></object></div><p>Drools permet de gérer les règles via une IHM grâce au composant Guvnor.</p><h4><a
name="CrationdunergleavecGuvnor"></a>Création d&#8217;une règle avec Guvnor</h4><div
align="center"> <a
href="http://blog.xebia.fr/wp-content/uploads/2010/01/guvnor01-creationduneregle.png"><br
/> <img
src="http://blog.xebia.fr/wp-content/uploads/2010/01/guvnor01-creationduneregle.png" border="0" alt=""  width="500"/><br
/> </a></div><h4><a
name="ModificationdunergleavecGuvnor"></a>Modification d&#8217;une règle avec Guvnor</h4><div
align="center"> <a
href="http://blog.xebia.fr/wp-content/uploads/2010/01/guvnor02-modificationDuneRegle.png"<br /> <img
src="http://blog.xebia.fr/wp-content/uploads/2010/01/guvnor02-modificationDuneRegle.png" border="0" alt="" width="500" /><br
/> </a></div><h4><a
name="GestiondunetablededcisionavecG"></a>Gestion d&#8217;une table de décision avec Guvnor</h4><div
align="center"> <a
href="http://blog.xebia.fr/wp-content/uploads/2010/01/guvnor03-TableDeDecision.png"<br /> <img
src="http://blog.xebia.fr/wp-content/uploads/2010/01/guvnor03-TableDeDecision.png" border="0" alt="" width="500" /><br
/> </a></div><div
class="shr-publisher-3730"></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div><div
class='shareaholic-like-buttonset' style='float:none;height:30px;'><a
class='shareaholic-googleplusone' data-shr_size='medium' data-shr_count='true' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2010%2F01%2F08%2Fdrools-et-les-moteurs-de-regles%2F' data-shr_title='Drools+et+les+moteurs+de+r%C3%A8gles'></a><a
class='shareaholic-tweetbutton' data-shr_count='horizontal' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2010%2F01%2F08%2Fdrools-et-les-moteurs-de-regles%2F' data-shr_title='Drools+et+les+moteurs+de+r%C3%A8gles'></a></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div>]]></content:encoded> <wfw:commentRss>http://blog.xebia.fr/2010/01/08/drools-et-les-moteurs-de-regles/feed/</wfw:commentRss> <slash:comments>7</slash:comments> </item> <item><title>Devoxx &#8211; Jour 2 &#8211; SOA en pratique</title><link>http://blog.xebia.fr/2009/11/23/devoxx-jour-2-soa-en-pratique/</link> <comments>http://blog.xebia.fr/2009/11/23/devoxx-jour-2-soa-en-pratique/#comments</comments> <pubDate>Mon, 23 Nov 2009 14:09:15 +0000</pubDate> <dc:creator>Michaël Figuière</dc:creator> <category><![CDATA[SOA]]></category> <category><![CDATA[Devoxx]]></category> <guid
isPermaLink="false">http://blog.xebia.fr/?p=3267</guid> <description><![CDATA[Les sessions dédiées à SOA étaient présentes cette année encore à Devoxx. Nicolai Josuttis a animé une présentation intitulée &#171;&#160;SOA in practice&#160;&#187; à l&#8217;image du titre du livre dont il est l&#8217;auteur, publié chez O&#8217;Reilly. Passage obligé de toute présentation sur SOA, Nicolai Josuttis commence par introduire l&#8217;ensemble des concepts gravitant autour de l&#8217;architecture orientée [...]]]></description> <content:encoded><![CDATA[<p><img
src="http://blog.xebia.fr/wp-content/uploads/2009/11/DSC_1491.jpg" style="margin: 1em 1em 1em 1em; float: right;" alt="Nicolai Josuttis" title="Nicolai Josuttis" /><br
/> Les sessions dédiées à SOA étaient présentes cette année encore à Devoxx. Nicolai Josuttis a animé une présentation intitulée &laquo;&nbsp;SOA in practice&nbsp;&raquo; à l&#8217;image du titre du livre dont il est l&#8217;auteur, <a
href="http://oreilly.com/catalog/9780596529550" title="publi chez OReilly" >publié chez O&#8217;Reilly</a>.</p><p>Passage obligé de toute présentation sur SOA, Nicolai Josuttis commence par introduire l&#8217;ensemble des concepts gravitant autour de l&#8217;architecture orientée services. Nous passerons sur ces rappels ici, car malgré quelques divergences dans les définitions, on retrouve les idées décrites dans <a
href="http://blog.xebia.fr/category/soa/" title="les diffrents articles portant sur SOA" >les différents articles portant sur SOA</a> que nous avons pu publier jusqu&#8217;alors.</p><p>Après cette introduction, Nicolai Josuttis s&#8217;est arrêté sur <a
href="http://blog.xebia.fr/2009/01/12/revue-de-presse-xebia-91/#Criselesanalystestuentletempsd" title="les dbats ayant agit le petit monde des SOAistes en ce dbut danne" >les débats ayant agité le petit monde des SOAistes en ce début d&#8217;année</a> : ce modèle d&#8217;architecture est-il mort ? N&#8217;était-ce qu&#8217;une mode de passage ? Non, le concept de service garde toute sa valeur pour l&#8217;entreprise et la suite de sa présentation, sans rien cacher des défauts de SOA, montrera tout son intérêt.</p><p>La suite de la présentation s&#8217;oriente rapidement autour de la mise en pratique de ces concepts.</p><p>&nbsp;<br
/> <br
/>&nbsp;</p><h3><a
name="SOAenpratiquedanslentreprise"></a>SOA en pratique dans l&#8217;entreprise</h3><h4><a
name="Entrefrontendsetbackends"></a>Entre <em>frontends</em> et <em>backends</em></h4><p>Une architecture orientée services repose en général sur un ensemble de <em>frontends</em> et une série de <em>backends</em> idéalement organisés en respectant les frontières des départements ou des <em>business units</em> de l&#8217;entreprise. La figure suivante représente ce type de système :</p><div
align="center"> <img
src="http://blog.xebia.fr/wp-content/uploads/2009/11/soa-in-practice.png" border="0" alt="" /></div><p>Le <em>frontend</em> peut prendre plusieurs formes. Il peut s&#8217;agir d&#8217;une simple interface de visualisation qui se contente alors de présenter les données formées par les services d&#8217;agrégation sous-jacents. A l&#8217;inverse, il peut permettre la modification des données, ce qui en fait une application plus intelligente. Il est alors également nécessaire de faire un choix quant à la validation des données entrantes : celle-ci peut se faire dans le <em>frontend</em>, dans le <em>frontend</em> et le <em>backend</em>, ou via un service dédié. Cette dernière solution simplifie l&#8217;architecture en assurant la cohérence de la validation mais entraîne une grande quantité d&#8217;invocations de services.</p><h4><a
name="Versionning"></a><em>Versionning</em></h4><p>Les services exposés dans une SOA subissent en général des modifications au cours de leur vie car ils mettent en œuvre des besoins en perpétuelle évolution. Les consommateurs ne pouvant alors être tous mis à jour lorsque le service évolue, <a
href="http://blog.xebia.fr/2008/05/21/les-10-pieges-de-la-soa-09-le-versioning/" title="plusieurs versions vont coexister" >plusieurs versions vont coexister</a>.</p><p>Nicolai Josuttis préconise alors de limiter à 3 le nombre de versions d&#8217;un même service en production. Pour cela :</p><ul><li>Il est nécessaire que les consommateurs d&#8217;une version obsolète d&#8217;un service fassent évoluer leur application afin d&#8217;exploiter la version la plus récente.</li><li>Le point précédent implique qu&#8217;une collaboration est nécessaire entre producteur et consommateur.</li><li>Il implique également qu&#8217;il est vital d&#8217;être en mesure d&#8217;énumérer l&#8217;ensemble des consommateurs d&#8217;un service.</li></ul><p>Interrogé sur le positionnement de nouveaux <em>framework</em> tels que <a
href="http://incubator.apache.org/thrift/" title="Apache Thrift" >Apache Thrift</a> gérant nativement la problématique de <em>versionning</em>, Nicolai Josuttis explique qu&#8217;il s&#8217;agit là d&#8217;un détail d&#8217;implémentation qui ne doit pas être une justification pour contourner le nombre maximum de versions simultanément en production.</p><h4><a
name="Rutilisabilit"></a>Ré-utilisabilité</h4><p>La <a
href="http://blog.xebia.fr/2009/04/16/soa-du-composant-au-service-la-reutilisabilite/" title="rutilisabilit" >ré-utilisabilité</a> est une des propriétés fondamentales des services dans une SOA.</p><p>Pourtant, Nicolai Josuttis a pu observer qu&#8217;en pratique cette propriété est rarement possible. En effet, il explique que ses observations ont montré que la majorité des services d&#8217;un système d&#8217;information ont au plus deux consommateurs. Certains ne sont même pas consommés.</p><p>Dans la mesure où la ré-utilisabilité va souvent à l&#8217;encontre des performances puisqu&#8217;il est alors souvent nécessaire d&#8217;invoquer plusieurs services, il est conseillé de se fixer des objectifs raisonnables quant à cette propriété.</p><h4><a
name="Annuaires"></a>Annuaires</h4><p>Les <a
href="http://blog.xebia.fr/2009/10/30/le-referentiel-de-services-dans-une-architecture-soa/" title="annuaires de services" >annuaires de services</a> permettent de recenser l&#8217;ensemble des services disponibles dans une SOA.</p><p>Nicolai Josuttis préconise de ne pas mettre en œuvre d&#8217;annuaire dès la création de l&#8217;architecture orientée services, mais d&#8217;attendre que le besoin s&#8217;en fasse naturellement ressentir.</p><h4><a
name="Gouvernance"></a>Gouvernance</h4><p>La SOA faisant interagir l&#8217;ensemble des départements de l&#8217;entreprise, des aspects humains et des problématiques de gouvernance surviennent inévitablement.</p><p>Il est suggéré de recourir à une équipe SOA dédiée, assurant le respect d&#8217;une stratégie d&#8217;architecture globale.</p><p>Lors de l&#8217;émergence de SOA dans l&#8217;entreprise, il est indispensable de procéder progressivement, en lançant des projets pilotes permettant de détecter les problématiques et d&#8217;adapter les équipes à cette nouvelle architecture. Ainsi le processus de transition peut prendre 5 ans.</p><h3><a
name="SOAlheuredubilan"></a>SOA à l&#8217;heure du bilan</h3><p>Après avoir énuméré l&#8217;ensemble de ces problématiques propres à SOA, Nicolai Josuttis pose une question simple : compte-tenu de tous ces défauts, pourquoi passer à SOA ? Il répond simplement en montrant que dans de nombreuses situations, ce modèle d&#8217;architecture n&#8217;est pas contournable pour satisfaire les besoins de communications entre les composantes de l&#8217;entreprise.</p><p>Enfin, il reconnait et dénonce le <em>hype</em> qui a entouré SOA, mais n&#8217;en minimise pas l&#8217;intérêt pour autant.</p><h3><a
name="Conclusion"></a>Conclusion</h3><p>L&#8217;architecture orientée services aurait-elle atteint la maturité ? C&#8217;est en tout cas l&#8217;impression qui transparaît face à la multiplication de présentations telles que celle de Nicolai Jusuttis, imprégnées de pragmatisme et de réalisme, tout en montrant son rôle incontournable dans le remplacement des systèmes monolithiques ou organisés en silos isolés.</p><p>L&#8217;apparition d&#8217;outils et de <em>frameworks</em> légers tranchant avec les solutions très lourdes que SOA a connu dans ses débuts, ainsi que la percée des méthodes agiles pour leur mise en œuvre, s&#8217;ajoutent à ces nouveaux discours pour constituer le renouveau des architectures orientées services.</p><div
class="shr-publisher-3267"></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div><div
class='shareaholic-like-buttonset' style='float:none;height:30px;'><a
class='shareaholic-googleplusone' data-shr_size='medium' data-shr_count='true' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2009%2F11%2F23%2Fdevoxx-jour-2-soa-en-pratique%2F' data-shr_title='Devoxx+-+Jour+2+-+SOA+en+pratique'></a><a
class='shareaholic-tweetbutton' data-shr_count='horizontal' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2009%2F11%2F23%2Fdevoxx-jour-2-soa-en-pratique%2F' data-shr_title='Devoxx+-+Jour+2+-+SOA+en+pratique'></a></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div>]]></content:encoded> <wfw:commentRss>http://blog.xebia.fr/2009/11/23/devoxx-jour-2-soa-en-pratique/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Le référentiel de services dans une architecture SOA</title><link>http://blog.xebia.fr/2009/10/30/le-referentiel-de-services-dans-une-architecture-soa/</link> <comments>http://blog.xebia.fr/2009/10/30/le-referentiel-de-services-dans-une-architecture-soa/#comments</comments> <pubDate>Fri, 30 Oct 2009 14:17:52 +0000</pubDate> <dc:creator>Christophe Heubès</dc:creator> <category><![CDATA[SOA]]></category> <category><![CDATA[Web Service]]></category> <guid
isPermaLink="false">http://blog.xebia.fr/?p=3052</guid> <description><![CDATA[Dans une architecture orientée service, le référentiel ou catalogue de services appartient à une famille de composants destinés à ce que l&#8217;on appelle généralement la gouvernance. La gouvernance est une notion évanescente, dont la définition fait l&#8217;objet d&#8217;âpres débats, mais qui, quelle que soit celle que l&#8217;on retient, renvoie au besoin de se doter d&#8217;outils [...]]]></description> <content:encoded><![CDATA[<p>Dans une architecture orientée service, le <strong>référentiel ou catalogue de services</strong> appartient à une famille de composants destinés à ce que l&#8217;on appelle généralement la <strong>gouvernance</strong>. La gouvernance est une notion évanescente, dont la définition fait l&#8217;objet d&#8217;âpres débats, mais qui, quelle que soit celle que l&#8217;on retient, renvoie au besoin de se doter d&#8217;outils et de procédures susceptibles d&#8217;<strong>assurer le contrôle de la complexité de l&#8217;architecture</strong> et d&#8217;en mesurer la consistance.</p><p>Le référentiel de service est un incontournable pour maîtriser les services.</p><p>Traditionnellement, et de façon macroscopique, un référentiel de services dans une architecture distribuée comprend deux grandes catégories de fonctionnalités :</p><ul><li>Les fonctions de <strong>registre</strong> qui visent à faciliter le fonctionnement de l&#8217;infrastructure de services :</li><ul><li>Contrôle d&#8217;accès.</li><li>Correspondance entre les différents noms que peut porter chaque service dans les différents sous-systèmes.</li><li>Localisation et routage.</li><li>Transcodification et uniformisation des codes <em>(y compris les codes erreurs)</em>.</li><li>&#8230;</li></ul><li>Les fonctions d&#8217;<strong>annuaire</strong> qui visent à consolider la connaissance métier :</li><ul><li>Etre la référence unique portant la connaissance des services de l&#8217;entreprise.</li><li>Porter la connaissance des formats d&#8217;échanges.</li><li>Distinguer les services qui nécessitent une réponse de ceux qui n&#8217;en attendent pas.</li><li>Identifier l&#8217;appartenance fonctionnelle de chaque flux.</li><li>Gérer les versions.</li><li>&#8230;</li></ul></ul><p>Les fonctions de registre sont destinées à l&#8217;exécution des services. Elles permettent aux consommateurs de services de localiser les fournisseurs <em>(dans la version adéquate)</em>, d&#8217;identifier les modalités techniques de l&#8217;interaction, de valider les formats d&#8217;échange et de vérifier les politiques d&#8217;accès. Elles adressent aussi la dimension routage à savoir qu&#8217;à partir des informations de contexte, elles offrent la possibilité de déterminer le service cible, le mode d&#8217;accès <em>(M.O.M., Web Services, &#8230;)</em>, les ressources associées <em>(nom de la file MQ, URL d&#8217;accès, etc.)</em>.<br
/> Ces fonctions de registre s&#8217;appuient le plus souvent sur le standard UDDI v3, et un ensemble de standards complémentaires pour les différentes métadonnées et stratégies <em>(WSDL 1.1, SOAP w/wo Attachement 1.1, OASIS Web Service Security, XACML 1.0, SAML 2.0)</em>.</p><p>Les fonctions d&#8217;annuaire, quant à elles, offrent une large palette de fonctionnalités destinées aux personnels impliqués dans la mise en œuvre de la SOA : modélisation et structuration du référentiel, accès à la documentation des services, recherche, gestion du cycle de vie <em>(éventuellement avec des processus d&#8217;approbation)</em>, analyse d&#8217;impact, reporting, etc. Ces fonctionnalités sont proposées au travers d&#8217;interfaces graphiques plus ou moins sophistiquées et ergonomiques.<br
/> Ces fonctions ne font pas l&#8217;objet de standards, et sont en conséquence un facteur de différenciation fort entre les offres logicielles.</p><p>Le référentiel assure donc la <strong>cohérence entre les différentes nomenclatures</strong> des applications.<br
/> Dans son acception classique, le référentiel doit être et rester l&#8217;<strong>unique point de référencement</strong> des services. Il constitue un composant central de l&#8217;architecture, et nécessite à ce titre des procédures de gestion et d&#8217;administration adaptées.</p><div
class="shr-publisher-3052"></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div><div
class='shareaholic-like-buttonset' style='float:none;height:30px;'><a
class='shareaholic-googleplusone' data-shr_size='medium' data-shr_count='true' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2009%2F10%2F30%2Fle-referentiel-de-services-dans-une-architecture-soa%2F' data-shr_title='Le+r%C3%A9f%C3%A9rentiel+de+services+dans+une+architecture+SOA'></a><a
class='shareaholic-tweetbutton' data-shr_count='horizontal' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2009%2F10%2F30%2Fle-referentiel-de-services-dans-une-architecture-soa%2F' data-shr_title='Le+r%C3%A9f%C3%A9rentiel+de+services+dans+une+architecture+SOA'></a></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div>]]></content:encoded> <wfw:commentRss>http://blog.xebia.fr/2009/10/30/le-referentiel-de-services-dans-une-architecture-soa/feed/</wfw:commentRss> <slash:comments>1</slash:comments> </item> <item><title>SOA : Du composant au service : La composabilité</title><link>http://blog.xebia.fr/2009/08/11/soa-du-composant-au-service-la-composabilite/</link> <comments>http://blog.xebia.fr/2009/08/11/soa-du-composant-au-service-la-composabilite/#comments</comments> <pubDate>Tue, 11 Aug 2009 07:50:46 +0000</pubDate> <dc:creator>Christophe Heubès</dc:creator> <category><![CDATA[SOA]]></category> <guid
isPermaLink="false">http://blog.xebia.fr/?p=2623</guid> <description><![CDATA[Comme son nom le suggère, l&#8217;élément clé de SOA (Service Oriented Architecture) est le Service. Il est pourtant difficile de faire le consensus autour de la notion de service et il est souvent difficile de répondre à cette simple question &#171;&#160;Qu&#8217;est-ce qu&#8217;un service ?&#160;&#187;. Ce sujet débouche invariablement sur, au choix : Un blanc ; [...]]]></description> <content:encoded><![CDATA[<p><a
href="http://blog.xebia.fr/wp-content/uploads/2009/03/composant-service.png"><img
src="http://blog.xebia.fr/wp-content/uploads/2009/03/composant-service-150x150.png" alt="composant-service" title="composant-service" width="150" height="150" style="margin: 1em 1em 1em 1em; float: right;" /></a><br
/> Comme son nom le suggère, l&#8217;élément clé de SOA <em>(Service Oriented Architecture)</em> est le <strong>Service</strong>. Il est pourtant difficile de faire le consensus autour de la notion de service et il est souvent difficile de répondre à cette simple question <em><strong>&laquo;&nbsp;Qu&#8217;est-ce qu&#8217;un service ?&nbsp;&raquo;</strong></em>. Ce sujet débouche invariablement sur, au choix : Un blanc ; Une réponse alambiquée et incertaine ; Une discussion enflammée <em>(ou un débat stérile)</em>.</p><p>On pourrait proposer la définition suivante : <em>&laquo;&nbsp;Un Service est un composant logiciel distribué, exposant les fonctionnalités à forte valeur ajoutée d&#8217;un domaine métier&nbsp;&raquo;</em>. Malheureusement, les définitions aussi courtes <em>(bien qu&#8217;exactes)</em> sont nécessairement incomplètes et amènent un florilège de questions.</p><p>Pour répondre plus précisément à la question, nous vous proposons de passer en revue les huit aspects qui caractérisent un service&nbsp;:</p><ul><li><a
href="http://blog.xebia.fr/2009/03/04/soa-du-composant-au-service-le-contrat-standardise/#more-1560">Contrat standardisé</a> : L&#8217;ensemble des services d&#8217;un même Système Technique sont exposés au travers de contrats respectant les mêmes règles de standardisation.</li><li><a
href="http://blog.xebia.fr/2009/03/19/soa-du-composant-au-service-le-couplage-lache/#more-1633">Couplage lâche</a> : Le contrat d&#8217;un service doit imposer un couplage lâche de ses clients.</li><li><a
href="http://blog.xebia.fr/2009/04/03/soa-du-composant-au-service-labstraction/#more-1706">Abstraction</a> : Le contrat d&#8217;un service ne doit contenir que les informations essentielles à son invocation. Seules ces informations doivent être publiées.</li><li><a
href="http://blog.xebia.fr/2009/04/16/soa-du-composant-au-service-la-reutilisabilite/#more-1780">Réutilisabilité</a> : Un service exprime une logique agnostique et peut ainsi être positionné comme une ressource réutilisable.</li><li><a
href="http://blog.xebia.fr/2009/04/29/soa-du-composant-au-service-lautonomie/#more-1852">Autonomie</a> : Un service doit exercer un contrôle fort sur son environnement d&#8217;exécution sous-jacent. Plus ce contrôle est fort, plus l&#8217;exécution d&#8217;un service est prédictible.</li><li><a
href="http://blog.xebia.fr/2009/06/04/soa-du-composant-au-service-sans-etat-stateless/#more-2134">Stateless</a> <em>(sans état)</em> : Un service doit minimiser la consommation de ressources en déléguant la gestion des informations d&#8217;état quand cela est nécessaire.</li><li><a
href="http://blog.xebia.fr/2009/06/12/soa-du-composant-au-service-la-decouvrabilite/#more-2196">Découvrabilité</a> : Un service est complété par un ensemble de métas données de communication au travers desquelles il peut être découvert et interprété de façon effective.</li><li><a
href="http://blog.xebia.fr/2009/08/11/soa-du-composant-au-service-la-composabilite/#more-2623">Composabilité</a> : Un service doit être conçu de façon à participer à des compositions de services.</li></ul><p>Ces 8 aspects sont issus du livre &laquo;&nbsp;<a
href="http://www.amazon.com/Principles-Service-Prentice-Service-Oriented-Computing/dp/0132344823">SOA Principles of Service Design</a>&nbsp;&raquo; de Thomas Erl, également auteur du site <a
href="http://www.soaprinciples.com/">SOA Principles</a>.</p><p>Dans ce billet, nous nous attarderons sur la notion de <a
href="http://blog.xebia.fr/2009/08/11/soa-du-composant-au-service-la-composabilite/#more-2623">composabilité</a>.</p><p>Un service doit être composable, c&#8217;est-à-dire être conçu de façon à participer à des compositions de services.</p><p>Ce huitième et dernier aspect constitue en quelque sorte l&#8217;aboutissement des sept précédents. En effet, l&#8217;ensemble des principes présentés dans cette série vise <em>in fine</em> à la <a
href="http://blog.xebia.fr/2009/04/16/soa-du-composant-au-service-la-reutilisabilite/" title="rutilisation des services" >réutilisation des services</a>. Or, cette réutilisabilité n&#8217;a de sens que si les services sont effectivement réutilisés en prenant part à des compositions de services.</p><p>C&#8217;est grâce à la composabilité que sera mis en œuvre le principe de <em><strong>&laquo;&nbsp;separation of concerns&nbsp;&raquo;</strong></em> au sein d&#8217;une architecture orientée services. L&#8217;objectif est ici de <a
href="http://blog.xebia.fr/2008/05/30/les-10-pieges-de-la-soa-07-mauvaise-granularite-des-services/" title="dterminer la bonne granularit de services" >déterminer la &laquo;&nbsp;bonne&nbsp;&raquo; granularité de services</a> afin de décomposer la solution à un problème métier de haut niveau en un ensemble de &laquo;&nbsp;plus petites unités réutilisables&nbsp;&raquo; de traitement : les services.<br
/> L&#8217;idée est de pouvoir <strong>recomposer notre logique métier à l&#8217;infini</strong> au sein de processus ou de services composites de haut niveau.</p><p>La mise en œuvre de cet aspect dans une architecture de services pose donc le problème du <strong>bon niveau de granularité pour un service</strong> :</p><ul><li>Un service trop large ne pourra pas être réutilisé, car il implémente un enchainement de traitements qui n&#8217;ont, a priori, de sens que dans le contexte où le service a été écrit. Un service trop large n&#8217;est utilisable que par une seule <em>(ou quelques)</em> application<em>(s)</em>.</li><li>A l&#8217;opposé, un service trop fin ne sera pas réutilisé, car il implémente un traitement atomique qui n&#8217;apporte pas de valeur ajoutée. Un service trop fin propose un niveau de détail qui n&#8217;est pas pertinent d&#8217;un point de vue métier.</li></ul><p>D&#8217;autre part, il faut garder à l&#8217;esprit que, d&#8217;un point de vue technique <em>(runtime)</em>, un service ne sera composable que s&#8217;il est <a
href="http://blog.xebia.fr/2009/04/29/soa-du-composant-au-service-lautonomie/#more-1852" title="autonome" >autonome</a> et <a
href="http://blog.xebia.fr/2009/06/04/soa-du-composant-au-service-sans-etat-stateless/#more-2134" title="stateless" >stateless</a> <em>(c&#8217;est-à-dire <a
href="http://blog.xebia.fr/2009/04/16/soa-du-composant-au-service-la-reutilisabilite/#more-1780" title="rutilisable" >réutilisable</a>)</em>.</p><p>Déterminer le niveau de granularité adéquat pour les services d&#8217;un écosystème est un exercice délicat, qui exige des connaissances <em>(en grande partie métier)</em>, de l&#8217;expertise et l&#8217;expérimentation de différentes options.<br
/> La réussite de cet exercice permettra de maximiser la composabilité du portfolio de services, pré-requis indispensable à l&#8217;atteinte d&#8217;un des objectifs phares de la mise en œuvre d&#8217;une architecture à base de services : la réutilisation des services en vue de l&#8217;<strong>agilisation du SI</strong>, indispensable à la <strong>réduction du time-to-market</strong>, principal élément de ROI des SOA.</p><div
class="shr-publisher-2623"></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div><div
class='shareaholic-like-buttonset' style='float:none;height:30px;'><a
class='shareaholic-googleplusone' data-shr_size='medium' data-shr_count='true' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2009%2F08%2F11%2Fsoa-du-composant-au-service-la-composabilite%2F' data-shr_title='SOA+%3A+Du+composant+au+service+%3A+La+composabilit%C3%A9'></a><a
class='shareaholic-tweetbutton' data-shr_count='horizontal' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2009%2F08%2F11%2Fsoa-du-composant-au-service-la-composabilite%2F' data-shr_title='SOA+%3A+Du+composant+au+service+%3A+La+composabilit%C3%A9'></a></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div>]]></content:encoded> <wfw:commentRss>http://blog.xebia.fr/2009/08/11/soa-du-composant-au-service-la-composabilite/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>SOA : Du composant au service : La découvrabilité</title><link>http://blog.xebia.fr/2009/06/12/soa-du-composant-au-service-la-decouvrabilite/</link> <comments>http://blog.xebia.fr/2009/06/12/soa-du-composant-au-service-la-decouvrabilite/#comments</comments> <pubDate>Fri, 12 Jun 2009 07:00:45 +0000</pubDate> <dc:creator>Christophe Heubès</dc:creator> <category><![CDATA[SOA]]></category> <guid
isPermaLink="false">http://blog.xebia.fr/?p=2196</guid> <description><![CDATA[Comme son nom le suggère, l&#8217;élément clé de SOA (Service Oriented Architecture) est le Service. Il est pourtant difficile de faire le consensus autour de la notion de service et il est souvent difficile de répondre à cette simple question &#171;&#160;Qu&#8217;est-ce qu&#8217;un service ?&#160;&#187;. Ce sujet débouche invariablement sur, au choix : Un blanc ; [...]]]></description> <content:encoded><![CDATA[<p><a
href="http://blog.xebia.fr/wp-content/uploads/2009/03/composant-service.png"><img
src="http://blog.xebia.fr/wp-content/uploads/2009/03/composant-service-150x150.png" alt="composant-service" title="composant-service" width="150" height="150" style="margin: 1em 1em 1em 1em; float: right;" /></a><br
/> Comme son nom le suggère, l&#8217;élément clé de SOA <em>(Service Oriented Architecture)</em> est le <strong>Service</strong>. Il est pourtant difficile de faire le consensus autour de la notion de service et il est souvent difficile de répondre à cette simple question <em><strong>&laquo;&nbsp;Qu&#8217;est-ce qu&#8217;un service ?&nbsp;&raquo;</strong></em>. Ce sujet débouche invariablement sur, au choix : Un blanc ; Une réponse alambiquée et incertaine ; Une discussion enflammée <em>(ou un débat stérile)</em>.</p><p>On pourrait proposer la définition suivante : <em>&laquo;&nbsp;Un Service est un composant logiciel distribué, exposant les fonctionnalités à forte valeur ajoutée d&#8217;un domaine métier&nbsp;&raquo;</em>. Malheureusement, les définitions aussi courtes <em>(bien qu&#8217;exactes)</em> sont nécessairement incomplètes et amènent un florilège de questions.</p><p>Pour répondre plus précisément à la question, nous vous proposons de passer en revue les huit aspects qui caractérisent un service&nbsp;:</p><ul><li><a
href="http://blog.xebia.fr/2009/03/04/soa-du-composant-au-service-le-contrat-standardise/#more-1560">Contrat standardisé</a> : L&#8217;ensemble des services d&#8217;un même Système Technique sont exposés au travers de contrats respectant les mêmes règles de standardisation.</li><li><a
href="http://blog.xebia.fr/2009/03/19/soa-du-composant-au-service-le-couplage-lache/#more-1633">Couplage lâche</a> : Le contrat d&#8217;un service doit imposer un couplage lâche de ses clients.</li><li><a
href="http://blog.xebia.fr/2009/04/03/soa-du-composant-au-service-labstraction/#more-1706">Abstraction</a> : Le contrat d&#8217;un service ne doit contenir que les informations essentielles à son invocation. Seules ces informations doivent être publiées.</li><li><a
href="http://blog.xebia.fr/2009/04/16/soa-du-composant-au-service-la-reutilisabilite/#more-1780">Réutilisabilité</a> : Un service exprime une logique agnostique et peut ainsi être positionné comme une ressource réutilisable.</li><li><a
href="http://blog.xebia.fr/2009/04/29/soa-du-composant-au-service-lautonomie/#more-1852">Autonomie</a> : Un service doit exercer un contrôle fort sur son environnement d&#8217;exécution sous-jacent. Plus ce contrôle est fort, plus l&#8217;exécution d&#8217;un service est prédictible.</li><li><a
href="http://blog.xebia.fr/2009/06/04/soa-du-composant-au-service-sans-etat-stateless/#more-2134">Stateless</a> <em>(sans état)</em> : Un service doit minimiser la consommation de ressources en déléguant la gestion des informations d&#8217;état quand cela est nécessaire.</li><li><a
href="http://blog.xebia.fr/2009/06/12/soa-du-composant-au-service-la-decouvrabilite/#more-2196">Découvrabilité</a> : Un service est complété par un ensemble de métas données de communication au travers desquelles il peut être découvert et interprété de façon effective.</li><li><a
href="http://blog.xebia.fr/2009/08/11/soa-du-composant-au-service-la-composabilite/#more-2623">Composabilité</a> : Un service doit être conçu de façon à participer à des compositions de services.</li></ul><p>Ces 8 aspects sont issus du livre &laquo;&nbsp;<a
href="http://www.amazon.com/Principles-Service-Prentice-Service-Oriented-Computing/dp/0132344823">SOA Principles of Service Design</a>&nbsp;&raquo; de Thomas Erl, également auteur du site <a
href="http://www.soaprinciples.com/">SOA Principles</a>.</p><p>Dans ce billet, nous nous attarderons sur la notion de &laquo;&nbsp;<a
href="http://blog.xebia.fr/2009/06/12/soa-du-composant-au-service-la-decouvrabilite/#more-2196">découvrabilité</a>&laquo;&nbsp;.</p><p>Nous l&#8217;avons dit et répété tout au long cette série, la <a
href="http://blog.xebia.fr/2009/04/16/soa-du-composant-au-service-la-reutilisabilite/" title="rutilisabilit des services" >réutilisabilité des services</a> constitue une des pierres angulaires de la mise en œuvre d&#8217;une architecture orientée service. En effet, la mise en œuvre d&#8217;une SOA vise, entre autres, à <strong>éviter le gaspillage</strong> des ressources en éliminant les redondances inhérentes au modèle en silo. D&#8217;autre part, la réutilisation est une condition première de l&#8217;<strong>agilisation du SI</strong> indispensable à la <strong>réduction du time-to-market</strong>, principal élément de ROI des SOA.</p><p>Le positionnement des <strong>services comme ressources réutilisables</strong> au sein de l&#8217;entreprise passe par :</p><ul><li>La <strong>prédictibilité des services</strong> proposés <em>(ce qui implique que les services soient <a
href="http://blog.xebia.fr/2009/04/29/soa-du-composant-au-service-lautonomie/#more-1852" title="autonomes">autonomes</a> et <a
href="http://blog.xebia.fr/2009/06/04/soa-du-composant-au-service-sans-etat-stateless/#more-2134/" title="sans état" >sans état</a>)</em>.</li><li>La <strong>découvrabilité des services</strong> existants.</li></ul><p>Écartons tout de suite le mythe de la découvrabilité au runtime qui reste un espoir inabouti <em>(ou une promesse non tenue)</em> : Un service répondant aux besoins et contraintes d&#8217;un consommateur potentiel ne peut être identifié que par un acteur humain. Nous parlons donc bien ici de <strong>découverte des services en phase de conception</strong>.</p><p>Cette découvrabilité des services existants passe par la mise en œuvre d&#8217;un <strong>repository de services</strong> qui vient outiller l&#8217;inventaire des services disponibles. Ce repository stocke l&#8217;ensemble des métadonnées nécessaires à :</p><ul><li>La recherche des services de l&#8217;inventaire.</li><li>La récupération de l&#8217;ensemble des artefacts relatifs aux services de l&#8217;inventaire <em>(Spécifications, SLAs, Policies, Schémas XML, WSDL, Interfaces, &#8230;)</em>.</li></ul><p><em>Remarque : Attention à ne pas confondre le repository de services avec un registre de services qui a lui la responsabilité de référencer pour le runtime les endpoints (points d&#8217;accès physiques) des services déployés.</em></p><p>Ainsi, le concepteur d&#8217;un consommateur de service <em>(Service composé, application composite, orchestration, processus, &#8230;)</em> pourra s&#8217;appuyer sur ce repository de la façon suivante :</p><ul><li>Le concepteur recherche dans le repository un service possédant les fonctionnalités dont il a besoin <em>(1)</em>.</li><li>En se basant sur les métadonnées contenues dans le repository, le concepteur est capable de découvrir et d&#8217;identifier un service potentiellement capable de répondre à ces besoins <em>(2)</em>.</li><li>le concepteur peut alors accéder au <a
href="http://blog.xebia.fr/2009/03/04/soa-du-composant-au-service-le-contrat-standardise/" title="contrat du service" >contrat du service</a> : syntaxique, sémantique et de niveau de service <em>(3)</em>. il est alors capable, en se basant sur les différents artefacts constituant le contrat du service <em>(spécifications, SLAs, policies, syntaxe,&nbsp;&#8230;)</em>, de déterminer si le service découvert correspond bien à ces attentes.</li></ul><div
align="center"> <img
src="http://blog.xebia.fr/wp-content/uploads/2009/06/decouvrabilite.png" border="0" alt="" /></div><p>Afin qu&#8217;il remplisse au mieux son rôle, les fonctionnalités attendues d&#8217;un repository de service sont :</p><ul><li>Le <strong>catalogage</strong> des services, de leurs métadonnées et des artéfacts relatifs à ces services.</li><li>La <strong>validation</strong> des services et artéfacts catalogués vis-à-vis des standards de l&#8217;entreprise.</li><li>La <strong>gestion des dépendances</strong> entre les services et les artéfacts.</li><li>Le <strong>versioning</strong> des services et de leurs différents artéfacts.</li><li>La <strong>gouvernance de la publication</strong> au sein du repository.</li><li>Le support d&#8217;un large panel de type d&#8217;artéfacts.</li></ul><p>Le repository de services constitue donc un outillage indispensable à la découvrabilité de l&#8217;inventaire des services. Il permet une gestion centralisée de l&#8217;ensemble des données relatives aux services, devenant ainsi un des éléments centraux autour desquels s&#8217;articulera la gouvernance SOA.</p><div
class="shr-publisher-2196"></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div><div
class='shareaholic-like-buttonset' style='float:none;height:30px;'><a
class='shareaholic-googleplusone' data-shr_size='medium' data-shr_count='true' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2009%2F06%2F12%2Fsoa-du-composant-au-service-la-decouvrabilite%2F' data-shr_title='SOA+%3A+Du+composant+au+service+%3A+La+d%C3%A9couvrabilit%C3%A9'></a><a
class='shareaholic-tweetbutton' data-shr_count='horizontal' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2009%2F06%2F12%2Fsoa-du-composant-au-service-la-decouvrabilite%2F' data-shr_title='SOA+%3A+Du+composant+au+service+%3A+La+d%C3%A9couvrabilit%C3%A9'></a></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div>]]></content:encoded> <wfw:commentRss>http://blog.xebia.fr/2009/06/12/soa-du-composant-au-service-la-decouvrabilite/feed/</wfw:commentRss> <slash:comments>1</slash:comments> </item> <item><title>SOA : Du composant au service : Sans état (Stateless)</title><link>http://blog.xebia.fr/2009/06/04/soa-du-composant-au-service-sans-etat-stateless/</link> <comments>http://blog.xebia.fr/2009/06/04/soa-du-composant-au-service-sans-etat-stateless/#comments</comments> <pubDate>Thu, 04 Jun 2009 04:32:16 +0000</pubDate> <dc:creator>Christophe Heubès</dc:creator> <category><![CDATA[SOA]]></category> <guid
isPermaLink="false">http://blog.xebia.fr/?p=2134</guid> <description><![CDATA[Comme son nom le suggère, l&#8217;élément clé de SOA (Service Oriented Architecture) est le Service. Il est pourtant difficile de faire le consensus autour de la notion de service et il est souvent difficile de répondre à cette simple question &#171;&#160;Qu&#8217;est-ce qu&#8217;un service ?&#160;&#187;. Ce sujet débouche invariablement sur, au choix : Un blanc ; [...]]]></description> <content:encoded><![CDATA[<p><a
href="http://blog.xebia.fr/wp-content/uploads/2009/03/composant-service.png"><img
src="http://blog.xebia.fr/wp-content/uploads/2009/03/composant-service-150x150.png" alt="composant-service" title="composant-service" width="150" height="150" style="margin: 1em 1em 1em 1em; float: right;" /></a><br
/> Comme son nom le suggère, l&#8217;élément clé de SOA <em>(Service Oriented Architecture)</em> est le <strong>Service</strong>. Il est pourtant difficile de faire le consensus autour de la notion de service et il est souvent difficile de répondre à cette simple question <em><strong>&laquo;&nbsp;Qu&#8217;est-ce qu&#8217;un service ?&nbsp;&raquo;</strong></em>. Ce sujet débouche invariablement sur, au choix : Un blanc ; Une réponse alambiquée et incertaine ; Une discussion enflammée <em>(ou un débat stérile)</em>.</p><p>On pourrait proposer la définition suivante : <em>&laquo;&nbsp;Un Service est un composant logiciel distribué, exposant les fonctionnalités à forte valeur ajoutée d&#8217;un domaine métier&nbsp;&raquo;</em>. Malheureusement, les définitions aussi courtes <em>(bien qu&#8217;exactes)</em> sont nécessairement incomplètes et amènent un florilège de questions.</p><p>Pour répondre plus précisément à la question, nous vous proposons de passer en revue les huit aspects qui caractérisent un service&nbsp;:</p><ul><li><a
href="http://blog.xebia.fr/2009/03/04/soa-du-composant-au-service-le-contrat-standardise/#more-1560">Contrat standardisé</a> : L&#8217;ensemble des services d&#8217;un même Système Technique sont exposés au travers de contrats respectant les mêmes règles de standardisation.</li><li><a
href="http://blog.xebia.fr/2009/03/19/soa-du-composant-au-service-le-couplage-lache/#more-1633">Couplage lâche</a> : Le contrat d&#8217;un service doit imposer un couplage lâche de ses clients.</li><li><a
href="http://blog.xebia.fr/2009/04/03/soa-du-composant-au-service-labstraction/#more-1706">Abstraction</a> : Le contrat d&#8217;un service ne doit contenir que les informations essentielles à son invocation. Seules ces informations doivent être publiées.</li><li><a
href="http://blog.xebia.fr/2009/04/16/soa-du-composant-au-service-la-reutilisabilite/#more-1780">Réutilisabilité</a> : Un service exprime une logique agnostique et peut ainsi être positionné comme une ressource réutilisable.</li><li><a
href="http://blog.xebia.fr/2009/04/29/soa-du-composant-au-service-lautonomie/#more-1852">Autonomie</a> : Un service doit exercer un contrôle fort sur son environnement d&#8217;exécution sous-jacent. Plus ce contrôle est fort, plus l&#8217;exécution d&#8217;un service est prédictible.</li><li><a
href="http://blog.xebia.fr/2009/06/04/soa-du-composant-au-service-sans-etat-stateless/#more-2134">Stateless</a> <em>(sans état)</em> : Un service doit minimiser la consommation de ressources en déléguant la gestion des informations d&#8217;état quand cela est nécessaire.</li><li><a
href="http://blog.xebia.fr/2009/06/12/soa-du-composant-au-service-la-decouvrabilite/#more-2196">Découvrabilité</a> : Un service est complété par un ensemble de métas données de communication au travers desquelles il peut être découvert et interprété de façon effective.</li><li><a
href="http://blog.xebia.fr/2009/08/11/soa-du-composant-au-service-la-composabilite/#more-2623">Composabilité</a> : Un service doit être conçu de façon à participer à des compositions de services.</li></ul><p>Ces 8 aspects sont issus du livre &laquo;&nbsp;<a
href="http://www.amazon.com/Principles-Service-Prentice-Service-Oriented-Computing/dp/0132344823">SOA Principles of Service Design</a>&nbsp;&raquo; de Thomas Erl, également auteur du site <a
href="http://www.soaprinciples.com/">SOA Principles</a>.</p><p>Dans ce billet, nous nous attarderons sur la notion de &laquo;&nbsp;<a
href="http://blog.xebia.fr/2009/06/04/soa-du-composant-au-service-sans-etat-stateless/#more-2134">statelessness</a>&laquo;&nbsp;.</p><p>Comme nous l&#8217;avons expliqué dans le précédent billet de cette série : Mettre l&#8217;emphase sur <a
href="http://blog.xebia.fr/2009/04/16/soa-du-composant-au-service-la-reutilisabilite/" title="la rutilisabilit des services" >la réutilisabilité des services</a> commence par la fourniture de services proposant une logique réutilisable, mais implique également que l&#8217;implémentation de cette logique soit effectivement réutilisable une fois déployée.<br
/> Dans une optique de <strong>sollicitation massive</strong>, il est important de concevoir l&#8217;implémentation des services en prêtant tout particulièrement attention à la <strong>concurrence d&#8217;accès</strong>. Les accès concurrents à un service ne doivent en aucun cas modifier son comportement, sa fiabilité ou ses performances. En d&#8217;autres termes, un service doit respecter son contrat <em>(et ses SLAs)</em>, quel que soit le volume de sollicitations auquel il est soumis : <strong>Un service doit être prédictible</strong>.<br
/> Afin de garantir cette prédictibilité dans le cadre d&#8217;accès concurrents, deux principes doivent être appliqués lors de l&#8217;élaboration des services :</p><ul><li>Un service doit <em>(au maximum)</em> être <strong>autonome</strong>.</li><li>Un service doit être <strong>sans état</strong>.</li></ul><p>Ces deux aspects sont fortement liés : Le principe d&#8217;<a
href="http://blog.xebia.fr/2009/04/29/soa-du-composant-au-service-lautonomie/" title="autonomie des services" >autonomie des services</a> implique que le comportement d&#8217;un service ne dépende pas du contexte dans lequel il est invoqué <em>(contexte fonctionnel ou contexte technique)</em>. Dans cette optique, intégrer de la gestion d&#8217;états au sein de nos services est un non sens.</p><p>D&#8217;une manière plus générale, la gestion d&#8217;états <em>(d&#8217;informations de contexte)</em> au sein d&#8217;un service pose des problèmes :</p><ul><li>De <a
href="http://blog.xebia.fr/2007/07/24/service-stateful-vs-service-stateless/#ComprehensionEtMaintenabilite" title="comprhension et de maintenabilit" >compréhension et de maintenabilité</a> :<br
/> La gestion d&#8217;états va sensiblement augmenter la complexité cyclomatique de l&#8217;implémentation et donc rendre difficile sa lecture, sa documentation, sa testabilité <em>(plus cette complexité cyclomatique est élevée, plus il est difficile d&#8217;obtenir une couverture de code acceptable)</em>, &#8230; Dans le cadre d&#8217;une composition de services, la complexité du composé étant directement liée à celle de ses composants, la complexité des services de plus haut niveau peut donc rapidement devenir ingérable.</li><li>De <a
href="http://blog.xebia.fr/2007/07/24/service-stateful-vs-service-stateless/#Reutilisation" title="rutilisation" >réutilisation</a> :<br
/> La gestion d&#8217;états au sein du service brouille la lisibilité de son contrat puisque l&#8217;adaptation de son comportement en fonction de son état ne transparaît pas dans son contrat. Or la lisibilité et la transparence des contrats de service sont des facteurs clés de la réutilisation des services.<br
/> D&#8217;autre part, l&#8217;utilisation d&#8217;états au sein d&#8217;un service présuppose souvent l&#8217;utilisation de ce service au sein d&#8217;un enchaînement d&#8217;invocations défini à l&#8217;avance. Il sera donc difficile de réutiliser le service au sein d&#8217;une autre orchestration ou composition.</li><li>De <a
href="http://blog.xebia.fr/2007/07/24/service-stateful-vs-service-stateless/#Performances" title="performances" >performances</a> : car la gestion des état est consommatrice de ressources systèmes, notamment en terme de stockage de ces états <em>(en mémoire ou sur disque)</em>.</li></ul><p><a
href="http://blog.xebia.fr/2007/07/24/service-stateful-vs-service-stateless/" title="On prfrera donc la conception et limplmentation de services stateless" >On préférera donc la conception et l&#8217;implémentation de services stateless</a>. La responsabilité de la gestion d&#8217;états sera alors déléguée aux utilisateurs <em>(consommateurs)</em> des services : compositions, orchestrations, processus, &#8230; Ce transfert de responsabilité <em>(déléguer la gestion d&#8217;états au client)</em> rejoint les principes d&#8217;une approche REST des services.</p><div
class="shr-publisher-2134"></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div><div
class='shareaholic-like-buttonset' style='float:none;height:30px;'><a
class='shareaholic-googleplusone' data-shr_size='medium' data-shr_count='true' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2009%2F06%2F04%2Fsoa-du-composant-au-service-sans-etat-stateless%2F' data-shr_title='SOA+%3A+Du+composant+au+service+%3A+Sans+%C3%A9tat+%28Stateless%29'></a><a
class='shareaholic-tweetbutton' data-shr_count='horizontal' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2009%2F06%2F04%2Fsoa-du-composant-au-service-sans-etat-stateless%2F' data-shr_title='SOA+%3A+Du+composant+au+service+%3A+Sans+%C3%A9tat+%28Stateless%29'></a></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div>]]></content:encoded> <wfw:commentRss>http://blog.xebia.fr/2009/06/04/soa-du-composant-au-service-sans-etat-stateless/feed/</wfw:commentRss> <slash:comments>1</slash:comments> </item> <item><title>Le retour sur investissement des infrastructures informatiques</title><link>http://blog.xebia.fr/2009/05/19/le-retour-sur-investissement-des-infrastructures-informatiques/</link> <comments>http://blog.xebia.fr/2009/05/19/le-retour-sur-investissement-des-infrastructures-informatiques/#comments</comments> <pubDate>Tue, 19 May 2009 07:02:38 +0000</pubDate> <dc:creator>Xebia France</dc:creator> <category><![CDATA[SOA]]></category> <guid
isPermaLink="false">http://blog.xebia.fr/?p=2014</guid> <description><![CDATA[Ce jeudi 14 mai, Guillaume Bodet (Directeur Technique de Xebia) était l&#8217;invité de l&#8217;émission 01 Business sur BFM Radio en compagnie d’Yves Caseau (Directeur général adjoint en charge de la prospective, de la qualité, des services et de l&#8217;innovation chez Bouygues Télécom, dont il est ancien DSI) et de Michel Mariet (Responsable marketing middleware d&#8217;Oracle [...]]]></description> <content:encoded><![CDATA[<p>Ce jeudi 14 mai, Guillaume Bodet <em>(Directeur Technique de Xebia)</em> était l&#8217;invité de l&#8217;émission <a
href="http://www.radiobfm.com/podcast/podcast.php?id=7" title="01 Business sur BFM Radio" >01 Business sur BFM Radio</a> en compagnie d’<a
href="http://organisationarchitecture.blogspot.com/" title="Yves Caseau" >Yves Caseau</a> <em>(Directeur général adjoint en charge de la prospective, de la qualité, des services et de l&#8217;innovation chez Bouygues Télécom, dont il est ancien DSI)</em> et de Michel Mariet <em>(Responsable marketing middleware d&#8217;Oracle France)</em>.</p><p>Le sujet de l’émission était <em>&laquo;&nbsp;<strong>Le retour sur investissement des infrastructures informatiques</strong>&laquo;&nbsp;</em> :</p><ul><li>Comment calculer le retour sur investissement <em>(ROI)</em> des infrastructures informatiques ?</li><li>Comment aligner ces infrastructures sur la stratégie de l’entreprise ?</li><li>Quel ROI apporte la mise en œuvre des SOA <em>(Architectures Orientées Services)</em> ?</li></ul><p>Bonne écoute.</p><p><script language="JavaScript" src="http://blog.xebia.fr/wp-content/uploads/2007/08/audio-player.js"></script></p><div
align="center"> <object
type="application/x-shockwave-flash" data="http://blog.xebia.fr/wp-content/uploads/2007/08/player.swf" id="20090514_business_bfm" height="24" width="600"><param
name="movie" value="http://blog.xebia.fr/wp-content/uploads/2007/08/player.swf"><param
name="FlashVars" value="playerID=20090514_business_bfm&amp;soundFile=http://blog.xebia.fr/wp-content/uploads/2009/05/20090514_business_bfm.mp3"><param
name="quality" value="high"><param
name="menu" value="false"><param
name="wmode" value="transparent"></object></div><div
class="shr-publisher-2014"></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div><div
class='shareaholic-like-buttonset' style='float:none;height:30px;'><a
class='shareaholic-googleplusone' data-shr_size='medium' data-shr_count='true' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2009%2F05%2F19%2Fle-retour-sur-investissement-des-infrastructures-informatiques%2F' data-shr_title='Le+retour+sur+investissement+des+infrastructures+informatiques'></a><a
class='shareaholic-tweetbutton' data-shr_count='horizontal' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2009%2F05%2F19%2Fle-retour-sur-investissement-des-infrastructures-informatiques%2F' data-shr_title='Le+retour+sur+investissement+des+infrastructures+informatiques'></a></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div>]]></content:encoded> <wfw:commentRss>http://blog.xebia.fr/2009/05/19/le-retour-sur-investissement-des-infrastructures-informatiques/feed/</wfw:commentRss> <slash:comments>0</slash:comments> <enclosure
url="http://blog.xebia.fr/wp-content/uploads/2009/05/20090514_business_bfm.mp3" length="22160893" type="audio/mpeg" /> </item> <item><title>SOA : Du composant au service : L&#8217;autonomie</title><link>http://blog.xebia.fr/2009/04/29/soa-du-composant-au-service-lautonomie/</link> <comments>http://blog.xebia.fr/2009/04/29/soa-du-composant-au-service-lautonomie/#comments</comments> <pubDate>Wed, 29 Apr 2009 07:00:13 +0000</pubDate> <dc:creator>Christophe Heubès</dc:creator> <category><![CDATA[SOA]]></category> <guid
isPermaLink="false">http://blog.xebia.fr/?p=1852</guid> <description><![CDATA[Comme son nom le suggère, l&#8217;élément clé de SOA (Service Oriented Architecture) est le Service. Il est pourtant difficile de faire le consensus autour de la notion de service et il est souvent difficile de répondre à cette simple question &#171;&#160;Qu&#8217;est-ce qu&#8217;un service ?&#160;&#187;. Ce sujet débouche invariablement sur, au choix : Un blanc ; [...]]]></description> <content:encoded><![CDATA[<p><a
href="http://blog.xebia.fr/wp-content/uploads/2009/03/composant-service.png"><img
src="http://blog.xebia.fr/wp-content/uploads/2009/03/composant-service-150x150.png" alt="composant-service" title="composant-service" width="150" height="150" style="margin: 1em 1em 1em 1em; float: right;" /></a><br
/> Comme son nom le suggère, l&#8217;élément clé de SOA <em>(Service Oriented Architecture)</em> est le <strong>Service</strong>. Il est pourtant difficile de faire le consensus autour de la notion de service et il est souvent difficile de répondre à cette simple question <em><strong>&laquo;&nbsp;Qu&#8217;est-ce qu&#8217;un service ?&nbsp;&raquo;</strong></em>. Ce sujet débouche invariablement sur, au choix : Un blanc ; Une réponse alambiquée et incertaine ; Une discussion enflammée <em>(ou un débat stérile)</em>.</p><p>On pourrait proposer la définition suivante : <em>&laquo;&nbsp;Un Service est un composant logiciel distribué, exposant les fonctionnalités à forte valeur ajoutée d&#8217;un domaine métier&nbsp;&raquo;</em>. Malheureusement, les définitions aussi courtes <em>(bien qu&#8217;exactes)</em> sont nécessairement incomplètes et amènent un florilège de questions.</p><p>Pour répondre plus précisément à la question, nous vous proposons de passer en revue les huit aspects qui caractérisent un service&nbsp;:</p><ul><li><a
href="http://blog.xebia.fr/2009/03/04/soa-du-composant-au-service-le-contrat-standardise/#more-1560">Contrat standardisé</a> : L&#8217;ensemble des services d&#8217;un même Système Technique sont exposés au travers de contrats respectant les mêmes règles de standardisation.</li><li><a
href="http://blog.xebia.fr/2009/03/19/soa-du-composant-au-service-le-couplage-lache/#more-1633">Couplage lâche</a> : Le contrat d&#8217;un service doit imposer un couplage lâche de ses clients.</li><li><a
href="http://blog.xebia.fr/2009/04/03/soa-du-composant-au-service-labstraction/#more-1706">Abstraction</a> : Le contrat d&#8217;un service ne doit contenir que les informations essentielles à son invocation. Seules ces informations doivent être publiées.</li><li><a
href="http://blog.xebia.fr/2009/04/16/soa-du-composant-au-service-la-reutilisabilite/#more-1780">Réutilisabilité</a> : Un service exprime une logique agnostique et peut ainsi être positionné comme une ressource réutilisable.</li><li><a
href="http://blog.xebia.fr/2009/04/29/soa-du-composant-au-service-lautonomie/#more-1852">Autonomie</a> : Un service doit exercer un contrôle fort sur son environnement d&#8217;exécution sous-jacent. Plus ce contrôle est fort, plus l&#8217;exécution d&#8217;un service est prédictible.</li><li><a
href="http://blog.xebia.fr/2009/06/04/soa-du-composant-au-service-sans-etat-stateless/#more-2134">Stateless</a> <em>(sans état)</em> : Un service doit minimiser la consommation de ressources en déléguant la gestion des informations d&#8217;état quand cela est nécessaire.</li><li><a
href="http://blog.xebia.fr/2009/06/12/soa-du-composant-au-service-la-decouvrabilite/#more-2196">Découvrabilité</a> : Un service est complété par un ensemble de métas données de communication au travers desquelles il peut être découvert et interprété de façon effective.</li><li><a
href="http://blog.xebia.fr/2009/08/11/soa-du-composant-au-service-la-composabilite/#more-2623">Composabilité</a> : Un service doit être conçu de façon à participer à des compositions de services.</li></ul><p>Ces 8 aspects sont issus du livre &laquo;&nbsp;<a
href="http://www.amazon.com/Principles-Service-Prentice-Service-Oriented-Computing/dp/0132344823">SOA Principles of Service Design</a>&nbsp;&raquo; de Thomas Erl, également auteur du site <a
href="http://www.soaprinciples.com/">SOA Principles</a>.</p><p>Dans ce billet, nous nous attarderons sur la notion d&#8217;<strong><a
href="http://blog.xebia.fr/2009/04/29/soa-du-composant-au-service-lautonomie/#more-1852">autonomie</a></strong>.</p><p>Comme nous l&#8217;avons vu dans le précédent billet de cette série : La <a
href="http://blog.xebia.fr/2009/04/16/soa-du-composant-au-service-la-reutilisabilite/" title="rutilisabilit des services" >réutilisabilité des services</a> constitue une des pierres angulaires de la mise en œuvre d&#8217;une architecture orientée service. En effet, la mise en œuvre d&#8217;une SOA vise, entre autres, à <strong>éviter le gaspillage</strong> des ressources en éliminant les redondances inhérentes au modèle en silo. D&#8217;autre part, la réutilisation est une condition première de l&#8217;<strong>agilisation du SI</strong> indispensable à la <strong>réduction du time-to-market</strong>, principal élément de ROI des SOA.<br
/> Mettre l&#8217;emphase sur la réutilisabilité des services commence bien sûr par la fourniture de services proposant une logique réutilisable, mais cela implique également que l&#8217;implémentation de cette logique soit effectivement réutilisable une fois déployée. La confrontation au monde réel est souvent douloureuse.<br
/> En effet, le modèle SOA pousse à maximiser les possibilités de réutilisation des services produits. Les services identifiés comme réutilisables sont ainsi mis à disposition d&#8217;un large spectre de services composites, de processus, d&#8217;applications, &#8230; Au fil du temps, de tels services ont donc vocation à prendre part à un nombre croissant de compositions, d&#8217;orchestrations, de workflow, &#8230;<br
/> Dans cette optique de <strong>sollicitation massive</strong>, il est donc important de concevoir l&#8217;implémentation des services en prêtant tout particulièrement attention à la <strong>concurrence d&#8217;accès</strong>. Les accès concurrents à un service ne doivent en aucun cas modifier son comportement, sa fiabilité ou ses performances. En d&#8217;autres termes, un service doit respecter son contrat <em>(et ses SLAs)</em>, quelque soit le volume de sollicitations auquel il est soumis : <strong>Un service doit être prédictible</strong>.</p><p>Afin de garantir cette prédictibilité dans le cadre d&#8217;accès concurrents, deux principes doivent être appliqués lors de l&#8217;élaboration des services :</p><ul><li>Un service doit <em>(au maximum)</em> être <strong>autonome</strong>.</li><li>Un service doit être <strong>sans état</strong>.</li></ul><p>Ces deux aspects sont fortement liés. En attendant le billet consacré à la notion de <em>&laquo;&nbsp;statelessness des services&nbsp;&raquo;</em>, je vous invite à relire l&#8217;article <a
href="http://blog.xebia.fr/2007/07/24/service-stateful-vs-service-stateless/" title="Service Stateful vs Service Stateless" >Service Stateful vs. Service Stateless</a>.</p><p>Afin que les services s&#8217;acquittent au mieux de leurs engagements <em>(comportement, fiabilité, performances, &#8230;)</em>, ils doivent exercer un contrôle fort sur leur environnement d&#8217;exécution et sur les ressources qui sous-tendent leur implémentation. L&#8217;autonomie d&#8217;un service traduit la mesure du degré de contrôle qu&#8217;un service exerce sur son environnement. Plus un service à de contrôle sur son environnement <em>(plus il est autonome)</em>, plus son comportement au runtime sera prévisible.<br
/> Lors de la décomposition des fonctions du SI en inventaire de services, il est souhaitable de définir les membres de ce registre comme des blocs indépendants. C&#8217;est donc un haut niveau d&#8217;autonomie individuelle des services qui est visé. Réduire l&#8217;accès partagé aux ressources d&#8217;un service et augmenter le niveau d&#8217;isolation physique des services sont deux leviers permettant d&#8217;augmenter cette capacité des services à fonctionner de façon autonome.</p><p>Tous les services d&#8217;un inventaire ne pourront évidement pas offrir un contrôle complet sur leur environnement. C&#8217;est pourquoi Thomas Erl propose de distinguer deux niveaux basiques d&#8217;autonomie :</p><ul><li>L&#8217;<strong>autonomie de niveau service</strong> : Les frontières des services entrant dans cette catégorie sont clairement définies et les services sont indépendants les uns des autres, mais il se peut que ces services partagent encore certaines ressources sur lesquelles ils s&#8217;appuient. Par exemple, un service d&#8217;encapsulation d&#8217;un système legacy, même s&#8217;il régit ce système partage cette ressource avec ses autres clients.</li><li>L&#8217;<strong>autonomie pure</strong> : La logique sous-jacente au service et les ressources qu&#8217;il utilise sont la propriété du service et sous son contrôle exclusif. C&#8217;est le niveau d&#8217;autonomie que l&#8217;on pourra atteindre lors de la création de <em>&laquo;&nbsp;nouveaux&nbsp;&raquo;</em> services quand la logique sous-jacente est construite spécifiquement pour supporter le service.</li></ul><p>La mise en œuvre d&#8217;une SOA se faisant, dans la grande majorité des cas, au sein d&#8217;un existant avec lequel il faut vivre pendant longtemps <em>(la refonte de tout ou partie du SI en mode big-bang est trop coûteuse et trop risquée)</em>, un inventaire de services offrant exclusivement des services d&#8217; un niveau d&#8217;autonomie pure reste un objectif difficilement atteignable. C&#8217;est pourtant cet objectif qu&#8217;il faut viser car un tel inventaire de service permet d&#8217;adresser nos préoccupations de monté en charge et de concurrence d&#8217;accès.</p><p>La mise en œuvre du principe d&#8217;autonomie est donc extrêmement importante car elle détermine dans quel mesure les autres principes peuvent être mis en application dans le monde réel <em>(nos environnements de production)</em> en favorisant la fiabilité et la prédictibilité des services.</p><div
class="shr-publisher-1852"></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div><div
class='shareaholic-like-buttonset' style='float:none;height:30px;'><a
class='shareaholic-googleplusone' data-shr_size='medium' data-shr_count='true' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2009%2F04%2F29%2Fsoa-du-composant-au-service-lautonomie%2F' data-shr_title='SOA+%3A+Du+composant+au+service+%3A+L%27autonomie'></a><a
class='shareaholic-tweetbutton' data-shr_count='horizontal' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2009%2F04%2F29%2Fsoa-du-composant-au-service-lautonomie%2F' data-shr_title='SOA+%3A+Du+composant+au+service+%3A+L%27autonomie'></a></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div>]]></content:encoded> <wfw:commentRss>http://blog.xebia.fr/2009/04/29/soa-du-composant-au-service-lautonomie/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>SOA : Du composant au service : La réutilisabilité</title><link>http://blog.xebia.fr/2009/04/16/soa-du-composant-au-service-la-reutilisabilite/</link> <comments>http://blog.xebia.fr/2009/04/16/soa-du-composant-au-service-la-reutilisabilite/#comments</comments> <pubDate>Thu, 16 Apr 2009 07:26:50 +0000</pubDate> <dc:creator>Christophe Heubès</dc:creator> <category><![CDATA[SOA]]></category> <guid
isPermaLink="false">http://blog.xebia.fr/?p=1780</guid> <description><![CDATA[Comme son nom le suggère, l&#8217;élément clé de SOA (Service Oriented Architecture) est le Service. Il est pourtant difficile de faire le consensus autour de la notion de service et il est souvent difficile de répondre à cette simple question &#171;&#160;Qu&#8217;est-ce qu&#8217;un service ?&#160;&#187;. Ce sujet débouche invariablement sur, au choix : Un blanc ; [...]]]></description> <content:encoded><![CDATA[<p><a
href="http://blog.xebia.fr/wp-content/uploads/2009/03/composant-service.png"><img
src="http://blog.xebia.fr/wp-content/uploads/2009/03/composant-service-150x150.png" alt="composant-service" title="composant-service" width="150" height="150" style="margin: 1em 1em 1em 1em; float: right;" /></a><br
/> Comme son nom le suggère, l&#8217;élément clé de SOA <em>(Service Oriented Architecture)</em> est le <strong>Service</strong>. Il est pourtant difficile de faire le consensus autour de la notion de service et il est souvent difficile de répondre à cette simple question <em><strong>&laquo;&nbsp;Qu&#8217;est-ce qu&#8217;un service ?&nbsp;&raquo;</strong></em>. Ce sujet débouche invariablement sur, au choix : Un blanc ; Une réponse alambiquée et incertaine ; Une discussion enflammée <em>(ou un débat stérile)</em>.</p><p>On pourrait proposer la définition suivante : <em>&laquo;&nbsp;Un Service est un composant logiciel distribué, exposant les fonctionnalités à forte valeur ajoutée d&#8217;un domaine métier&nbsp;&raquo;</em>. Malheureusement, les définitions aussi courtes <em>(bien qu&#8217;exactes)</em> sont nécessairement incomplètes et amènent un florilège de questions.</p><p>Pour répondre plus précisément à la question, nous vous proposons de passer en revue les huit aspects qui caractérisent un service&nbsp;:</p><ul><li><a
href="http://blog.xebia.fr/2009/03/04/soa-du-composant-au-service-le-contrat-standardise/#more-1560">Contrat standardisé</a> : L&#8217;ensemble des services d&#8217;un même Système Technique sont exposés au travers de contrats respectant les mêmes règles de standardisation.</li><li><a
href="http://blog.xebia.fr/2009/03/19/soa-du-composant-au-service-le-couplage-lache/#more-1633">Couplage lâche</a> : Le contrat d&#8217;un service doit imposer un couplage lâche de ses clients.</li><li><a
href="http://blog.xebia.fr/2009/04/03/soa-du-composant-au-service-labstraction/#more-1706">Abstraction</a> : Le contrat d&#8217;un service ne doit contenir que les informations essentielles à son invocation. Seules ces informations doivent être publiées.</li><li><a
href="http://blog.xebia.fr/2009/04/16/soa-du-composant-au-service-la-reutilisabilite/#more-1780">Réutilisabilité</a> : Un service exprime une logique agnostique et peut ainsi être positionné comme une ressource réutilisable.</li><li><a
href="http://blog.xebia.fr/2009/04/29/soa-du-composant-au-service-lautonomie/#more-1852">Autonomie</a> : Un service doit exercer un contrôle fort sur son environnement d&#8217;exécution sous-jacent. Plus ce contrôle est fort, plus l&#8217;exécution d&#8217;un service est prédictible.</li><li><a
href="http://blog.xebia.fr/2009/06/04/soa-du-composant-au-service-sans-etat-stateless/#more-2134">Stateless</a> <em>(sans état)</em> : Un service doit minimiser la consommation de ressources en déléguant la gestion des informations d&#8217;état quand cela est nécessaire.</li><li><a
href="http://blog.xebia.fr/2009/06/12/soa-du-composant-au-service-la-decouvrabilite/#more-2196">Découvrabilité</a> : Un service est complété par un ensemble de métas données de communication au travers desquelles il peut être découvert et interprété de façon effective.</li><li><a
href="http://blog.xebia.fr/2009/08/11/soa-du-composant-au-service-la-composabilite/#more-2623">Composabilité</a> : Un service doit être conçu de façon à participer à des compositions de services.</li></ul><p>Ces 8 aspects sont issus du livre &laquo;&nbsp;<a
href="http://www.amazon.com/Principles-Service-Prentice-Service-Oriented-Computing/dp/0132344823">SOA Principles of Service Design</a>&nbsp;&raquo; de Thomas Erl, également auteur du site <a
href="http://www.soaprinciples.com/">SOA Principles</a>.</p><p>Dans ce billet, nous nous attarderons sur la notion de <strong>réutilisabilité</strong>.</p><p>La réutilisabilité des services <em>(et plus largement des ressources du SI)</em> constitue une des pierres angulaires de la mise en œuvre d&#8217;une architecture orientée service. En effet, la mise en œuvre d&#8217;une SOA vise, entre autres, à <strong>éviter le gaspillage</strong> des ressources en éliminant les redondances inhérentes au modèle en silo. D&#8217;autre part, la réutilisation <em>(et donc la réutilisabilité)</em> est une condition première de l&#8217;<strong>agilisation du SI</strong> indispensable à la <strong>réduction du time-to-market</strong>, principal élément de ROI des SOA.</p><p>La production de services réutilisables passe par la combinaison des processus d&#8217;ingénierie logicielle traditionnels et des processus de production industrielle à destination de la consommation de masse. En effet, même si les méthodologues n&#8217;ont de cesse de proposer un mode de production standard des projets informatiques, force est de constater que le cycle de production d&#8217;un projet informatique lui est souvent spécifique. Les logiciels ainsi produits sont destinés à un usage précis au sein du SI et proposent un potentiel de réutilisabilité quasi nul. A l&#8217;inverse, les chaines de production pour l&#8217;industrie de masse visent à la production de produits génériques et standardisés offrant un fort potentiel de réutilisabilité.<br
/> L&#8217;objectif est de produire un registre de services offrant un très fort potentiel de réutilisabilité et qui soit effectivement réutilisé <em>(cette deuxième partie étant souvent plus difficile)</em>.</p><p>Pour ce faire, il est essentiel de mettre en application le concept de <strong>centralisation de la logique métier</strong> qui veut que chaque fonction logique offerte par le SI ne soit accessible que par un seul point d&#8217;entrée (1) : le service qui l&#8217;implémente. Cette approche est indispensable au <strong>positionnement des services comme ressources réutilisables au sein de l&#8217;entreprise</strong>.</p><div
align="center"> <img
src="http://blog.xebia.fr/wp-content/uploads/2009/04/reutilisation.png" border="0" alt="" /></div><p>La combinaison de la <a
href="http://blog.xebia.fr/2009/03/04/soa-du-composant-au-service-le-contrat-standardise/#more-1560" title="centralisation des contrats de service" >centralisation des contrats de service</a> <em>(qui garantie qu&#8217;un consommateur n&#8217;a accès au service que par son contrat (2))</em> et de cette centralisation de la logique métier permet d&#8217;obtenir un inventaire de services hautement normalisé. La standardisation de cet inventaire est essentielle pour maximiser la réutilisabilité <em>(et la réutilisation)</em> des services disponibles au sein de l&#8217;entreprise. Elle facilitera également le <a
href="http://blog.xebia.fr/2009/03/19/soa-du-composant-au-service-le-couplage-lache/#more-1633" title="couplage lche des consommateurs aux services" >couplage lâche des consommateurs aux services</a>.</p><p>Ainsi, <strong>les processus organisationnels de production logiciels doivent êtres revus</strong> pour garantir la centralisation de la logique métier. Lors de la conception d&#8217;un processus ou d&#8217;un service composite, ces processus organisationnels doivent inclure systématiquement une recherche dans l&#8217;inventaire des services existants. Si la logique métier recherchée existe déjà dans cet inventaire, le service qui l&#8217;implémente doit être réutilisé. Dans le cas contraire, son implémentation doit être faite sous forme de service avec une vision élargie <em>(plus large que sa simple utilisation dans le cadre du processus concerné)</em>.<br
/> C&#8217;est pourquoi, comme nous l&#8217;expliquions dans &laquo;&nbsp;<a
href="http://blog.xebia.fr/2007/08/16/mise-en-oeuvre-dune-soa-les-cles-du-succes/" title="Mise en uvre dune SOA  Les cls du succs" >Mise en œuvre d&#8217;une SOA : Les clés du succès</a>&laquo;&nbsp;, la mise en place d&#8217;une SOA est un effort <em>(une initiative)</em> qui doit être mené de façon transverse. Elle ne peut pas être traitée projet par projet.</p><p>Le principal frein à la réutilisation des services est la <strong>résistance au changement</strong> et les guerres de chapelle.<br
/> Comme le faisait remarquer Bruno en commentaire au billet &laquo;&nbsp;<a
href="http://blog.xebia.fr/2009/03/04/soa-du-composant-au-service-le-contrat-standardise/#comments" title="SOA : Du composant au service : Le contrat standardisé" >SOA : Du composant au service : Le contrat standardisé</a>&laquo;&nbsp;, <em>&laquo;&nbsp;dans une organisation multi-partite on n&#8217;utilise pas un service parce qu&#8217;il existe, mais parce qu&#8217;on en a le droit ; et ce droit est donné par un/des urbanistes qui gèrent de facto les mises en relation.&nbsp;&raquo;</em>. C&#8217;est en effet le cas dans certaines organisations. On retombe ici dans <a
href="http://blog.xebia.fr/2008/06/24/les-10-pieges-de-la-soa-02-propriete-des-composants-et-financement-au-projet/" title="les travers lis  la proprit des composants et au financement au projet" >les travers liés à la propriété des composants et au financement au projet</a>.<br
/> C&#8217;est malheureusement pour cela que dans de nombreuses structures <em>(notamment les plus larges)</em>, la réutilisation effective des services reste un vœu pieux.</p><div
class="shr-publisher-1780"></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div><div
class='shareaholic-like-buttonset' style='float:none;height:30px;'><a
class='shareaholic-googleplusone' data-shr_size='medium' data-shr_count='true' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2009%2F04%2F16%2Fsoa-du-composant-au-service-la-reutilisabilite%2F' data-shr_title='SOA+%3A+Du+composant+au+service+%3A+La+r%C3%A9utilisabilit%C3%A9'></a><a
class='shareaholic-tweetbutton' data-shr_count='horizontal' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2009%2F04%2F16%2Fsoa-du-composant-au-service-la-reutilisabilite%2F' data-shr_title='SOA+%3A+Du+composant+au+service+%3A+La+r%C3%A9utilisabilit%C3%A9'></a></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div>]]></content:encoded> <wfw:commentRss>http://blog.xebia.fr/2009/04/16/soa-du-composant-au-service-la-reutilisabilite/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>SOA : Du composant au service : L&#8217;abstraction</title><link>http://blog.xebia.fr/2009/04/03/soa-du-composant-au-service-labstraction/</link> <comments>http://blog.xebia.fr/2009/04/03/soa-du-composant-au-service-labstraction/#comments</comments> <pubDate>Fri, 03 Apr 2009 08:56:15 +0000</pubDate> <dc:creator>Christophe Heubès</dc:creator> <category><![CDATA[SOA]]></category> <guid
isPermaLink="false">http://blog.xebia.fr/?p=1706</guid> <description><![CDATA[Comme son nom le suggère, l&#8217;élément clé de SOA (Service Oriented Architecture) est le Service. Il est pourtant difficile de faire le consensus autour de la notion de service et il est souvent difficile de répondre à cette simple question &#171;&#160;Qu&#8217;est-ce qu&#8217;un service ?&#160;&#187;. Ce sujet débouche invariablement sur, au choix : Un blanc ; [...]]]></description> <content:encoded><![CDATA[<p><a
href="http://blog.xebia.fr/wp-content/uploads/2009/03/composant-service.png"><img
src="http://blog.xebia.fr/wp-content/uploads/2009/03/composant-service-150x150.png" alt="composant-service" title="composant-service" width="150" height="150" style="margin: 1em 1em 1em 1em; float: right;" /></a><br
/> Comme son nom le suggère, l&#8217;élément clé de SOA <em>(Service Oriented Architecture)</em> est le <strong>Service</strong>. Il est pourtant difficile de faire le consensus autour de la notion de service et il est souvent difficile de répondre à cette simple question <em><strong>&laquo;&nbsp;Qu&#8217;est-ce qu&#8217;un service ?&nbsp;&raquo;</strong></em>. Ce sujet débouche invariablement sur, au choix : Un blanc ; Une réponse alambiquée et incertaine ; Une discussion enflammée <em>(ou un débat stérile)</em>.</p><p>On pourrait proposer la définition suivante : <em>&laquo;&nbsp;Un Service est un composant logiciel distribué, exposant les fonctionnalités à forte valeur ajoutée d&#8217;un domaine métier&nbsp;&raquo;</em>. Malheureusement, les définitions aussi courtes <em>(bien qu&#8217;exactes)</em> sont nécessairement incomplètes et amènent un florilège de questions.</p><p>Pour répondre plus précisément à la question, nous vous proposons de passer en revue les huit aspects qui caractérisent un service&nbsp;:</p><ul><li><a
href="http://blog.xebia.fr/2009/03/04/soa-du-composant-au-service-le-contrat-standardise/#more-1560">Contrat standardisé</a> : L&#8217;ensemble des services d&#8217;un même Système Technique sont exposés au travers de contrats respectant les mêmes règles de standardisation.</li><li><a
href="http://blog.xebia.fr/2009/03/19/soa-du-composant-au-service-le-couplage-lache/#more-1633">Couplage lâche</a> : Le contrat d&#8217;un service doit imposer un couplage lâche de ses clients.</li><li><a
href="http://blog.xebia.fr/2009/04/03/soa-du-composant-au-service-labstraction/#more-1706">Abstraction</a> : Le contrat d&#8217;un service ne doit contenir que les informations essentielles à son invocation. Seules ces informations doivent être publiées.</li><li><a
href="http://blog.xebia.fr/2009/04/16/soa-du-composant-au-service-la-reutilisabilite/#more-1780">Réutilisabilité</a> : Un service exprime une logique agnostique et peut ainsi être positionné comme une ressource réutilisable.</li><li><a
href="http://blog.xebia.fr/2009/04/29/soa-du-composant-au-service-lautonomie/#more-1852">Autonomie</a> : Un service doit exercer un contrôle fort sur son environnement d&#8217;exécution sous-jacent. Plus ce contrôle est fort, plus l&#8217;exécution d&#8217;un service est prédictible.</li><li><a
href="http://blog.xebia.fr/2009/06/04/soa-du-composant-au-service-sans-etat-stateless/#more-2134">Stateless</a> <em>(sans état)</em> : Un service doit minimiser la consommation de ressources en déléguant la gestion des informations d&#8217;état quand cela est nécessaire.</li><li><a
href="http://blog.xebia.fr/2009/06/12/soa-du-composant-au-service-la-decouvrabilite/#more-2196">Découvrabilité</a> : Un service est complété par un ensemble de métas données de communication au travers desquelles il peut être découvert et interprété de façon effective.</li><li><a
href="http://blog.xebia.fr/2009/08/11/soa-du-composant-au-service-la-composabilite/#more-2623">Composabilité</a> : Un service doit être conçu de façon à participer à des compositions de services.</li></ul><p>Ces 8 aspects sont issus du livre &laquo;&nbsp;<a
href="http://www.amazon.com/Principles-Service-Prentice-Service-Oriented-Computing/dp/0132344823">SOA Principles of Service Design</a>&nbsp;&raquo; de Thomas Erl, également auteur du site <a
href="http://www.soaprinciples.com/">SOA Principles</a>.</p><p>Dans ce billet, nous nous attarderons sur la notion d&#8217;<strong><a
href="http://blog.xebia.fr/2009/04/03/soa-du-composant-au-service-labstraction/#more-1706">abstraction</a></strong>.</p><p>Le principe d&#8217;abstraction consiste à fournir les services du SI sur un modèle <strong>boîte noire</strong>.<br
/> Dans ce modèle, les <strong>seules</strong> informations accessibles aux consommateurs d&#8217;un service sont celles contenues dans son contrat. Ainsi, les concepteurs et développeurs d&#8217;un consommateur de service ne sont pas au courant de la façon dont est implémenté le service.<br
/> C&#8217;est pourquoi, nous l&#8217;avons vu, il est important d&#8217;assurer <a
href="http://blog.xebia.fr/2009/03/19/soa-du-composant-au-service-le-couplage-lache/" title="un couplage lche des consommateurs aux services" >un couplage lâche des consommateurs aux services</a>. Dans ce modèle, il est également très important d&#8217;assurer la <strong>prédictibilité d&#8217;un service</strong> : le comportement d&#8217;un service et la réponse qu&#8217;il donne à une requête ne doit pas varier. Cette prédictibilité du service est induite par le respect de son contrat.</p><p>Le principe d&#8217;abstraction promeut donc l&#8217;offuscation délibérée d&#8217;un ensemble de données relatives aux services exposés afin qu&#8217;un minimum d&#8217;information soit accessible aux consommateurs potentiels.</p><div
align="center"> <img
src="http://blog.xebia.fr/wp-content/uploads/2009/04/services-abstraction.png" border="0" alt="" /></div><p>Ainsi, il est <em>(par exemple)</em> préférable de ne pas diffuser les détails de conception et d&#8217;implémentation d&#8217;un service et de proposer ici un accès contrôlé. Même, si les développeurs ayant le réflexe de se plonger dans le code source des plateformes qu&#8217;ils utilisent sont malheureusement trop rares, cette mesure <strong>encourage le positionnement des services en tant que ressources agnostiques et réutilisables</strong>. Elle contribue également à <strong>forger une relation de confiance entre producteurs et consommateurs de services</strong> ou tout du moins leur &laquo;&nbsp;impose&nbsp;&raquo; de dialoguer, ce qui ne peut pas être mauvais.</p><div
class="shr-publisher-1706"></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div><div
class='shareaholic-like-buttonset' style='float:none;height:30px;'><a
class='shareaholic-googleplusone' data-shr_size='medium' data-shr_count='true' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2009%2F04%2F03%2Fsoa-du-composant-au-service-labstraction%2F' data-shr_title='SOA+%3A+Du+composant+au+service+%3A+L%27abstraction'></a><a
class='shareaholic-tweetbutton' data-shr_count='horizontal' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2009%2F04%2F03%2Fsoa-du-composant-au-service-labstraction%2F' data-shr_title='SOA+%3A+Du+composant+au+service+%3A+L%27abstraction'></a></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div>]]></content:encoded> <wfw:commentRss>http://blog.xebia.fr/2009/04/03/soa-du-composant-au-service-labstraction/feed/</wfw:commentRss> <slash:comments>1</slash:comments> </item> <item><title>SOA : Du composant au service : Le couplage lâche</title><link>http://blog.xebia.fr/2009/03/19/soa-du-composant-au-service-le-couplage-lache/</link> <comments>http://blog.xebia.fr/2009/03/19/soa-du-composant-au-service-le-couplage-lache/#comments</comments> <pubDate>Thu, 19 Mar 2009 09:31:39 +0000</pubDate> <dc:creator>Christophe Heubès</dc:creator> <category><![CDATA[SOA]]></category> <guid
isPermaLink="false">http://blog.xebia.fr/?p=1633</guid> <description><![CDATA[Comme son nom le suggère, l&#8217;élément clé de SOA (Service Oriented Architecture) est le Service. Il est pourtant difficile de faire le consensus autour de la notion de service et il est souvent difficile de répondre à cette simple question &#171;&#160;Qu&#8217;est-ce qu&#8217;un service ?&#160;&#187;. Ce sujet débouche invariablement sur, au choix : Un blanc ; [...]]]></description> <content:encoded><![CDATA[<p><a
href="http://blog.xebia.fr/wp-content/uploads/2009/03/composant-service.png"><img
src="http://blog.xebia.fr/wp-content/uploads/2009/03/composant-service-150x150.png" alt="composant-service" title="composant-service" width="150" height="150" style="margin: 1em 1em 1em 1em; float: right;" /></a><br
/> Comme son nom le suggère, l&#8217;élément clé de SOA <em>(Service Oriented Architecture)</em> est le <strong>Service</strong>. Il est pourtant difficile de faire le consensus autour de la notion de service et il est souvent difficile de répondre à cette simple question <em><strong>&laquo;&nbsp;Qu&#8217;est-ce qu&#8217;un service ?&nbsp;&raquo;</strong></em>. Ce sujet débouche invariablement sur, au choix : Un blanc ; Une réponse alambiquée et incertaine ; Une discussion enflammée <em>(ou un débat stérile)</em>.</p><p>On pourrait proposer la définition suivante : <em>&laquo;&nbsp;Un Service est un composant logiciel distribué, exposant les fonctionnalités à forte valeur ajoutée d&#8217;un domaine métier&nbsp;&raquo;</em>. Malheureusement, les définitions aussi courtes <em>(bien qu&#8217;exactes)</em> sont nécessairement incomplètes et amènent un florilège de questions.</p><p>Pour répondre plus précisément à la question, nous vous proposons de passer en revue les huit aspects qui caractérisent un service&nbsp;:</p><ul><li><a
href="http://blog.xebia.fr/2009/03/04/soa-du-composant-au-service-le-contrat-standardise/#more-1560">Contrat standardisé</a> : L&#8217;ensemble des services d&#8217;un même Système Technique sont exposés au travers de contrats respectant les mêmes règles de standardisation.</li><li><a
href="http://blog.xebia.fr/2009/03/19/soa-du-composant-au-service-le-couplage-lache/#more-1633">Couplage lâche</a> : Le contrat d&#8217;un service doit imposer un couplage lâche de ses clients.</li><li><a
href="http://blog.xebia.fr/2009/04/03/soa-du-composant-au-service-labstraction/#more-1706">Abstraction</a> : Le contrat d&#8217;un service ne doit contenir que les informations essentielles à son invocation. Seules ces informations doivent être publiées.</li><li><a
href="http://blog.xebia.fr/2009/04/16/soa-du-composant-au-service-la-reutilisabilite/#more-1780">Réutilisabilité</a> : Un service exprime une logique agnostique et peut ainsi être positionné comme une ressource réutilisable.</li><li><a
href="http://blog.xebia.fr/2009/04/29/soa-du-composant-au-service-lautonomie/#more-1852">Autonomie</a> : Un service doit exercer un contrôle fort sur son environnement d&#8217;exécution sous-jacent. Plus ce contrôle est fort, plus l&#8217;exécution d&#8217;un service est prédictible.</li><li><a
href="http://blog.xebia.fr/2009/06/04/soa-du-composant-au-service-sans-etat-stateless/#more-2134">Stateless</a> <em>(sans état)</em> : Un service doit minimiser la consommation de ressources en déléguant la gestion des informations d&#8217;état quand cela est nécessaire.</li><li><a
href="http://blog.xebia.fr/2009/06/12/soa-du-composant-au-service-la-decouvrabilite/#more-2196">Découvrabilité</a> : Un service est complété par un ensemble de métas données de communication au travers desquelles il peut être découvert et interprété de façon effective.</li><li><a
href="http://blog.xebia.fr/2009/08/11/soa-du-composant-au-service-la-composabilite/#more-2623">Composabilité</a> : Un service doit être conçu de façon à participer à des compositions de services.</li></ul><p>Ces 8 aspects sont issus du livre &laquo;&nbsp;<a
href="http://www.amazon.com/Principles-Service-Prentice-Service-Oriented-Computing/dp/0132344823">SOA Principles of Service Design</a>&nbsp;&raquo; de Thomas Erl, également auteur du site <a
href="http://www.soaprinciples.com/">SOA Principles</a>.</p><p>Dans ce billet, nous nous attarderons sur la notion de <strong><a
href="http://blog.xebia.fr/2009/03/19/soa-du-composant-au-service-le-couplage-lache/#more-1633">couplage lâche</a></strong>.</p><p>Comme nous l&#8217;expliquions dans notre livre blanc &laquo;&nbsp;<a
href="http://blog.xebia.fr/2007/10/16/livre-blanc-comprendre-et-savoir-utiliser-un-esb-dans-une-soa/" title="Comprendre et savoir utiliser un ESB dans une SOA" >Comprendre et savoir utiliser un ESB dans une SOA</a>&laquo;&nbsp;, la formalisation du paradigme SOA a clairement eu le mérite de replacer le métier au centre de l&#8217;architecture du SI. Mais SOA reste aussi un projet d&#8217;intégration à grande échelle. Il est dès lors primordial d&#8217;éviter les chausse-trappes des grands projets d&#8217;architectures distribuées ou intégrées, et en particulier le couplage technique et fonctionnel entre consommateurs et fournisseurs de services.<br
/> Le couplage technique impose au consommateur de connaître le protocole d&#8217;échange du fournisseur. À grande échelle, un tel couplage complique, voire interdit l&#8217;évolution du socle technique, et risque de figer le SI dans une inertie sclérosante.<br
/> À la fois plus subtil et plus pernicieux, le couplage fonctionnel impose au client de connaître le format d&#8217;échange du fournisseur. Toute évolution du fournisseur a un impact potentiel sur chacun de ses consommateurs. Mal gérée, cette dépendance peut conduire à de véritables verrous fonctionnels dans le Système d&#8217;Informations &#8211; interdisant toute évolution ou, plus sûrement, augmentant de façon exponentielle le coût de ces évolutions.</p><h4><a
name="Limplmentationdunservicedpendd"></a>L&#8217;implémentation d&#8217;un service dépend de son environnement</h4><p>C&#8217;est une évidence, la logique d&#8217;un service est, par nature, fortement liée à son environnement :</p><ul><li>Tout d&#8217;abord, la logique d&#8217;un service est directement dépendante de son implémentation <em>(1)</em>. Cette implémentation s&#8217;appuie sur un ensemble de ressources qui constituent l&#8217;environnement d&#8217;implémentation du service. La logique d&#8217;un service est donc couplée à ces ressources.</li><li>De la même façon, la logique d&#8217;un service est fortement liée aux technologies sur lesquelles son implémentation s&#8217;adosse <em>(2)</em>.</li><li>D&#8217;autre part, dans le cadre de services composites, la logique d&#8217;un service est également dépendante des services qui le composent <em>(3)</em>.</li><li>Enfin, le contrat de service ainsi que sa logique peuvent être couplés aux processus qui les utilisent <em>(4)</em>.</li></ul><p>Ces couplages sont inévitables.</p><div
align="center"> <img
src="http://blog.xebia.fr/wp-content/uploads/2009/03/couplage-01.png" border="0" alt="" /></div><h4><a
name="LecouplageContratService"></a>Le couplage Contrat / Service</h4><p>Le contrat d&#8217;un service et sa logique peuvent être couplés de deux façons différentes :</p><ul><li> <strong>Couplage du contrat de service vers la logique d&#8217;implémentation du service <em>(B)</em> :</strong><br
/> Un tel couplage résulte d&#8217;une approche <strong>contract last</strong> lors du design du service <em>(le contrat dérive de l&#8217;implémentation)</em>. Cette approche, nous allons le voir, est à proscrire car elle induit un couplage du contrat avec l&#8217;environnement du service.</li><li> <strong>Couplage de la logique du service au contrat <em>(A)</em> :</strong><br
/> Ce couplage dénote une approche <strong>contract first</strong> dans la conception du service <em>(le contrat est écrit préalablement à l&#8217;implémentation du service)</em>. Cette approche est toujours préférable et le couplage du service vers son contrat est considéré comme un couplage positif.</li></ul><h4><a
name="tablirladpendancedanslebonsens"></a>Établir la dépendance dans le bon sens</h4><p>Les consommateurs d&#8217;un service sont liés au contrat de ce dernier, et ne doivent être liés qu&#8217;à celui-ci <em>(Pas au service lui-même)</em>. C&#8217;est ce que l&#8217;on appelle le <strong>couplage lâche</strong>.<br
/> Or, si le contrat est couplé avec la logique du service <em>(B)</em>, les consommateurs vont hériter par transitivité de l&#8217;ensemble des dépendances de la logique du service avec son environnement. Nous nous retrouvons donc avec <strong>des consommateurs qui sont fortement couplés au service</strong>.</p><div
align="center"> <img
src="http://blog.xebia.fr/wp-content/uploads/2009/03/couplage-02.png" border="0" alt="" /></div><p>C&#8217;est pourquoi il est préférable d&#8217;établir le couplage du service vers son contrat <em>(A)</em>.</p><h4><a
name="Perspectives"></a>Perspectives</h4><p>Les équipes en charge de la conception des consommateurs ne sont pas nécessairement au courant du couplage du contrat à la logique <em>(B)</em>. Ainsi, une telle situation aboutit à un ensemble de couplages non désirés et ignorés des consommateurs à l&#8217;environnement du service.<br
/> La prolifération de tels couplages est catastrophique car ils <strong>fragilisent</strong> et <strong>rendent moins flexible</strong> l&#8217;ensemble de l&#8217;architecture de service <em>(SOA)</em>. C&#8217;est pourquoi, <strong>les approches contract last sont à proscrire</strong>.<br
/> À l&#8217;inverse, <strong>les approches contract first sont à encourager</strong> car elles permettent d&#8217;imposer <em>(via le contrat)</em> un couplage lâche des clients au service, permettant ainsi l&#8217;évolution des implémentations sans impact sur les consommateurs.</p><div
class="shr-publisher-1633"></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div><div
class='shareaholic-like-buttonset' style='float:none;height:30px;'><a
class='shareaholic-googleplusone' data-shr_size='medium' data-shr_count='true' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2009%2F03%2F19%2Fsoa-du-composant-au-service-le-couplage-lache%2F' data-shr_title='SOA+%3A+Du+composant+au+service+%3A+Le+couplage+l%C3%A2che'></a><a
class='shareaholic-tweetbutton' data-shr_count='horizontal' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2009%2F03%2F19%2Fsoa-du-composant-au-service-le-couplage-lache%2F' data-shr_title='SOA+%3A+Du+composant+au+service+%3A+Le+couplage+l%C3%A2che'></a></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div>]]></content:encoded> <wfw:commentRss>http://blog.xebia.fr/2009/03/19/soa-du-composant-au-service-le-couplage-lache/feed/</wfw:commentRss> <slash:comments>3</slash:comments> </item> <item><title>SOA : Du composant au service : Le contrat standardisé</title><link>http://blog.xebia.fr/2009/03/04/soa-du-composant-au-service-le-contrat-standardise/</link> <comments>http://blog.xebia.fr/2009/03/04/soa-du-composant-au-service-le-contrat-standardise/#comments</comments> <pubDate>Wed, 04 Mar 2009 09:20:35 +0000</pubDate> <dc:creator>Christophe Heubès</dc:creator> <category><![CDATA[SOA]]></category> <category><![CDATA[Web Service]]></category> <category><![CDATA[WS-I]]></category> <guid
isPermaLink="false">http://blog.xebia.fr/?p=1560</guid> <description><![CDATA[Comme son nom le suggère, l&#8217;élément clé de SOA (Service Oriented Architecture) est le Service. Il est pourtant difficile de faire le consensus autour de la notion de service et il est souvent difficile de répondre à cette simple question &#171;&#160;Qu&#8217;est-ce qu&#8217;un service ?&#160;&#187;. Ce sujet débouche invariablement sur, au choix : Un blanc ; [...]]]></description> <content:encoded><![CDATA[<p><a
href="http://blog.xebia.fr/wp-content/uploads/2009/03/composant-service.png"><img
src="http://blog.xebia.fr/wp-content/uploads/2009/03/composant-service-150x150.png" alt="composant-service" title="composant-service" width="150" height="150" style="margin: 1em 1em 1em 1em; float: right;" /></a><br
/> Comme son nom le suggère, l&#8217;élément clé de SOA <em>(Service Oriented Architecture)</em> est le <strong>Service</strong>. Il est pourtant difficile de faire le consensus autour de la notion de service et il est souvent difficile de répondre à cette simple question <em><strong>&laquo;&nbsp;Qu&#8217;est-ce qu&#8217;un service ?&nbsp;&raquo;</strong></em>. Ce sujet débouche invariablement sur, au choix : Un blanc ; Une réponse alambiquée et incertaine ; Une discussion enflammée <em>(ou un débat stérile)</em>.</p><p>On pourrait proposer la définition suivante : <em>&laquo;&nbsp;Un Service est un composant logiciel distribué, exposant les fonctionnalités à forte valeur ajoutée d&#8217;un domaine métier&nbsp;&raquo;</em>. Malheureusement, les définitions aussi courtes <em>(bien qu&#8217;exactes)</em> sont nécessairement incomplètes et amènent un florilège de questions.</p><p>Pour répondre plus précisément à la question, nous vous proposons de passer en revue les huit aspects qui caractérisent un service&nbsp;:</p><ul><li><a
href="http://blog.xebia.fr/2009/03/04/soa-du-composant-au-service-le-contrat-standardise/#more-1560">Contrat standardisé</a> : L&#8217;ensemble des services d&#8217;un même Système Technique sont exposés au travers de contrats respectant les mêmes règles de standardisation.</li><li><a
href="http://blog.xebia.fr/2009/03/19/soa-du-composant-au-service-le-couplage-lache/#more-1633">Couplage lâche</a> : Le contrat d&#8217;un service doit imposer un couplage lâche de ses clients.</li><li><a
href="http://blog.xebia.fr/2009/04/03/soa-du-composant-au-service-labstraction/#more-1706">Abstraction</a> : Le contrat d&#8217;un service ne doit contenir que les informations essentielles à son invocation. Seules ces informations doivent être publiées.</li><li><a
href="http://blog.xebia.fr/2009/04/16/soa-du-composant-au-service-la-reutilisabilite/#more-1780">Réutilisabilité</a> : Un service exprime une logique agnostique et peut ainsi être positionné comme une ressource réutilisable.</li><li><a
href="http://blog.xebia.fr/2009/04/29/soa-du-composant-au-service-lautonomie/#more-1852">Autonomie</a> : Un service doit exercer un contrôle fort sur son environnement d&#8217;exécution sous-jacent. Plus ce contrôle est fort, plus l&#8217;exécution d&#8217;un service est prédictible.</li><li><a
href="http://blog.xebia.fr/2009/06/04/soa-du-composant-au-service-sans-etat-stateless/#more-2134">Stateless</a> <em>(sans état)</em> : Un service doit minimiser la consommation de ressources en déléguant la gestion des informations d&#8217;état quand cela est nécessaire.</li><li><a
href="http://blog.xebia.fr/2009/06/12/soa-du-composant-au-service-la-decouvrabilite/#more-2196">Découvrabilité</a> : Un service est complété par un ensemble de métas données de communication au travers desquelles il peut être découvert et interprété de façon effective.</li><li><a
href="http://blog.xebia.fr/2009/08/11/soa-du-composant-au-service-la-composabilite/#more-2623">Composabilité</a> : Un service doit être conçu de façon à participer à des compositions de services.</li></ul><p>Ces 8 aspects sont issus du livre &laquo;&nbsp;<a
href="http://www.amazon.com/Principles-Service-Prentice-Service-Oriented-Computing/dp/0132344823">SOA Principles of Service Design</a>&nbsp;&raquo; de Thomas Erl, également auteur du site <a
href="http://www.soaprinciples.com/">SOA Principles</a>.</p><p>Dans ce premier billet, nous nous attarderons sur la notion de <strong><a
href="http://blog.xebia.fr/2009/03/04/soa-du-composant-au-service-le-contrat-standardise/#more-1560">contrat standardisé</a></strong>.</p><h4><a
name="Questcequuncontratdeservice"></a>Qu&#8217;est-ce qu&#8217;un contrat de service ?</h4><p>Le contrat de service définit un accord entre le fournisseur et le consommateur. Il est composé :</p><ul><li>D&#8217;un <strong>contrat syntaxique</strong> qui propose une représentation technique du service :<br
/> Il constitue le contrat d&#8217;utilisation du service <em>(son interface)</em>. Il présente le nom du traitement, ses paramètres d&#8217;entrée et de sortie et les contraintes structurelles <em>(format et contrainte sur les données)</em> qui s&#8217;y appliquent.</li><li>D&#8217;un <strong>contrat sémantique</strong> qui fournit une description informelle du traitement :<br
/> Il précise les règles et contraintes d&#8217;utilisation du service : La valorisation des messages de réponse <em>(0 représente-t-il le résultat d&#8217;un calcul, une erreur, une interruption de service ?)</em> ; Les exceptions ; les pré et post conditions techniques <em>(ex. : volume des données échangées)</em> ou métiers <em>(ex. : écriture comptable équilibrée)</em>.</li><li>D&#8217;un <strong>contrat de niveau de service</strong> <em>(QoS &#038; SLA)</em> qui précise les engagements du service :<br
/> Il spécifie par exemple le temps de réponse maximum attendu, les plages horaires d&#8217;accessibilité, le temps de reprise après interruption, les procédures mises en œuvre en cas de panne, les procédures de prise en charge du support, &#8230;</li></ul><p>Par exemple, lorsqu&#8217;un service est implémenté sous forme de Web Service <em>(nous parlons bien ici d&#8217;un exemple ; il ne faut pas confondre service et Web Service)</em>, son contrat est composé :</p><ul><li>D&#8217;une WSDL qui décrit les modalités d&#8217;accès au(x) service(s) :<br
/> La WSDL fait partie du contrat syntaxique. Elle fournit l&#8217;interface du service.</li><li>D&#8217;un ensemble de XSD qui définissent les types de données échangées par le service :<br
/> Les XSD font partie du contrat syntaxique. Elles définissent les formats de données et les contraintes structurelles.<br
/> Les XSD font également partie du contrat sémantique. En effet, la richesse des types et restrictions XSD permet d&#8217;auto-documenter les valeurs possibles et permet souvent d&#8217;éviter des quiproquos.</li><li>D&#8217;un ensemble de policies qui définissent les règles d&#8217;utilisation du service :<br
/> Les policies font parties du contrat sémantique. Les règles et contraintes qu&#8217;elles expriment adressent des domaines variés : Sécurité, encodage, langue, versioning, métiers, &#8230;</li><li>De documentations complémentaires.<br
/> Ces documentations complètent le contrat sémantique. C&#8217;est par exemple dans les spécifications que l&#8217;on décrira les pré et post condition d&#8217;utilisation du service <em>(elles ne sont pas toutes implémentables sous forme de policy)</em>.<br
/> Ces documentations constituent le contrat de niveau de service <em>(QoS &#038; SLA)</em>. Notons que l&#8217;on parle bien d&#8217;un contrat qui définit un ensemble d&#8217;indicateurs et de valeurs seuils. Il n&#8217;est pas question ici des moyens techniques à mettre en œuvre pour leur supervision <em>(traces, alertes, &#8230;)</em>.</li></ul><div
align="center"> <img
src="http://blog.xebia.fr/wp-content/uploads/2009/03/contrat-service.png" border="0" alt="" /></div><h4><a
name="Standardiserpourfaciliterlacom"></a>Standardiser pour faciliter la communication</h4><p>Le contrat de service est donc une notion complexe qui ne se limite pas à la <em>(simple)</em> définition d&#8217;interfaces. Un contrat de service est constitué de nombreux éléments <em>(techniques ou non)</em> qui forment un fond documentaire pour lequel il est préférable <em>(voire indispensable)</em> de respecter un formalisme commun. L&#8217;utilisation de ce formalisme commun est le meilleur moyen de construire un modèle cohérent et donc facile à comprendre et à partager.</p><p>La notion de contrat de service standardisé ramène à celle de <strong>contract first</strong> qui est, comme nous l&#8217;évoquions dans notre billet sur l&#8217;<a
href=" http://blog.xebia.fr/2009/02/18/web-service-interoperability-ws-i/" title="interoprabilit des Web Services" >interopérabilité des Web Services</a> <em>(sans, une fois de plus, limiter la notion de service à ceux-ci)</em>, la meilleure approche de conception de services <em>(voire la seule valable ?)</em>. Dans cette approche, les contrats font l&#8217;objet de développements spécifiques en amont de l&#8217;implémentation de la logique du service. Le développement de ces contrats doit se faire suivant des règles de standardisation établies pour l&#8217;ensemble des services d&#8217;un même Système Technique.</p><h4><a
name="Centraliserpourencouragerlarut"></a>Centraliser pour encourager la réutilisation</h4><p>En plus de cadrer la définition des contrats <em>(et donc de faciliter la communication)</em>, l&#8217;utilisation d&#8217;un formalisme commun et de règles de standardisations facilite la centralisation des éléments constituant les contrats. Cette centralisation encourage la réutilisation. Parmi les constituants des contrats de services, deux sont de particulièrement bons candidats à la réutilisation :</p><ul><li>Les règles d&#8217;utilisation <em>(policies)</em> :<br
/> Les contraintes de sécurité, d&#8217;encodage, de versioning sont souvent communes à l&#8217;ensemble <em>(ou à un sous-ensemble)</em> des services d&#8217;un domaine. De la même façon, les règles métiers sont rarement applicables à un seul service.</li><li>Les formats de données <em>(XSDs)</em> :<br
/> Il est évident que les types et formats de données sont utilisés par plusieurs services. Ces derniers ont même vocation à être utilisés au-delà des services : les types et formats de données sont souvent les mêmes pour les invocations synchrones de service et pour les échanges asynchrones, par exemple au travers d&#8217;un bus.</li></ul><p>Pour rendre possible leur <strong>réutilisation</strong>, il est indispensable de séparer les différents éléments du contrat de service. Plusieurs WSDL pourront ainsi appliquer les mêmes règles <em>(policies)</em> et manipuler les mêmes types de données <em>(XSDs)</em>.</p><div
align="center"> <img
src="http://blog.xebia.fr/wp-content/uploads/2009/03/contrat-centralisation.png" border="0" alt="" /></div><p>L&#8217;isolation des différents constituants du contrat de service en vue de leur réalisation est une bonne pratique qui tient du bon sens. Il n&#8217;est pourtant pas rare de voir des déclarations de type <em>(XSDs)</em> au sein d&#8217;une WSDL plutôt qu&#8217;un import. Cette approche est aussi aberrante que la re-déclaration en inner class de l&#8217;ensemble des types de données manipulés par un Bean <em>(Cette pratique doit être restreinte à des cas bien spécifiques et constituer une exception)</em>.</p><h4><a
name="Perspectives"></a>Perspectives</h4><p>La standardisation des contrats de service est donc un élément fondamental de la mise en œuvre d&#8217;architectures orientées services <em>(SOA)</em>. En effet, la mise en place des bonnes pratiques évoquées dans ce billet offre des gains importants sur deux axes clés :</p><ul><li><strong>Faciliter la communication et le partage de la connaissance</strong> :<br
/> La définition d&#8217;un ensemble de principes communs de conception des contrats <em>(ex. : conventions de nommage claires pour les entités, les attributs et les relations)</em> permet d&#8217;aboutir à un modèle plus cohérent et donc plus facile à comprendre, partager, (ré)utiliser.</li><li><strong>Encourager la réutilisation</strong> :<br
/> L&#8217;isolation et la centralisation des différents constituants des contrats de services facilitent indéniablement leur réutilisation.</li></ul><p>Il ne faut pas perdre de vue que la définition de certains de ces éléments dépasse le simple cadre des contrats de service. Il est par exemple souhaitable que les types et formats de données manipulés par les services soient également utilisés au sein des flux d&#8217;intégration. Cette pratique, même si la <a
href="http://blog.xebia.fr/2008/06/17/les-10-pieges-de-la-soa-04-mauvaise-utilisation-des-modeles-de-donnees-canoniques-pivots/" title="dfinition dun Modle de Donnes Canonique" >définition d&#8217;un Modèle de Données Canonique</a> reste un exercice difficile, est un gage sur le long terme de maintenabilité, de stabilité et de pérennité.</p><div
class="shr-publisher-1560"></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div><div
class='shareaholic-like-buttonset' style='float:none;height:30px;'><a
class='shareaholic-googleplusone' data-shr_size='medium' data-shr_count='true' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2009%2F03%2F04%2Fsoa-du-composant-au-service-le-contrat-standardise%2F' data-shr_title='SOA+%3A+Du+composant+au+service+%3A+Le+contrat+standardis%C3%A9'></a><a
class='shareaholic-tweetbutton' data-shr_count='horizontal' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2009%2F03%2F04%2Fsoa-du-composant-au-service-le-contrat-standardise%2F' data-shr_title='SOA+%3A+Du+composant+au+service+%3A+Le+contrat+standardis%C3%A9'></a></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div>]]></content:encoded> <wfw:commentRss>http://blog.xebia.fr/2009/03/04/soa-du-composant-au-service-le-contrat-standardise/feed/</wfw:commentRss> <slash:comments>5</slash:comments> </item> <item><title>Web Service Interoperability (WS-I)</title><link>http://blog.xebia.fr/2009/02/18/web-service-interoperability-ws-i/</link> <comments>http://blog.xebia.fr/2009/02/18/web-service-interoperability-ws-i/#comments</comments> <pubDate>Wed, 18 Feb 2009 07:42:59 +0000</pubDate> <dc:creator>Christophe Heubès</dc:creator> <category><![CDATA[SOA]]></category> <category><![CDATA[Web Service]]></category> <category><![CDATA[WS-I]]></category> <guid
isPermaLink="false">http://blog.xebia.fr/?p=1499</guid> <description><![CDATA[L&#8217;objectif initial des Web Services est de fournir un ensemble de standards permettant d&#8217;exposer des services de manière interopérable. La mode du tout Web Service a rapidement mis en exergue les manques du triptyque de départ (WSDL, SOAP, UDDI) qui n&#8217;est plus qu&#8217;un diptyque. Par exemple, les aspects transactionnels en sont absents, ce qui impose [...]]]></description> <content:encoded><![CDATA[<p>L&#8217;objectif initial des Web Services est de fournir un ensemble de standards permettant d&#8217;exposer des services de manière interopérable.<br
/> La mode du tout Web Service a rapidement mis en exergue les manques du triptyque de départ <em>(WSDL, SOAP, UDDI)</em> qui n&#8217;est plus qu&#8217;un diptyque. Par exemple, les aspects transactionnels en sont absents, ce qui impose de gérer des mécanismes de compensation. C&#8217;est alors que se sont mis à fleurir les WS-*. Même après consolidation et épuration, la confusion autour de ces standards est palpable et il semble illusoire d&#8217;aboutir à un modèle qui soit interpéropérable out-of-the-box.<br
/> C&#8217;est face à ce constat que s&#8217;est créée la <a
href="http://www.ws-i.org/" title="Web Service Interoperability Organization" >Web Service Interoperability Organization</a> <em>(WS-I org.)</em>, consortium industriel dont l&#8217;objectif est d&#8217;établir et de diffuser un ensemble de best practices autour des standards Web Service, en vue de garantir l&#8217;interopérabilité des différentes implémentations et utilisations qui sont faites de cette pile de standards.</p><p>Dans ce billet, nous reviendrons rapidement sur <a
href="http://blog.xebia.fr/2009/02/18/web-service-interoperability-ws-i/#LagalaxiedesstandardsWebServic" title="la galaxie des standards Web Services" >la galaxie des standards Web Services</a>, avant de présenter <a
href="http://blog.xebia.fr/2009/02/18/web-service-interoperability-ws-i/#WebServiceInteroperabilityOrga" title="la Web Service Interoperability Organization" >la Web Service Interoperability Organization</a> <em>(WS-I org.)</em> et ses travaux.<br
/> Nous nous attarderons ensuite sur <a
href="http://blog.xebia.fr/2009/02/18/web-service-interoperability-ws-i/#Lesprofils" title="les profils proposés par le WS-I" >les profils proposés par le WS-I</a> puis sur <a
href="http://blog.xebia.fr/2009/02/18/web-service-interoperability-ws-i/#Lesoutils" title="les outils quil met  disposition" >les outils qu&#8217;il met à disposition</a>.<br
/> Nous terminerons avec <a
href="http://blog.xebia.fr/2009/02/18/web-service-interoperability-ws-i/#Perspectives" title="quelques recommandations" >quelques recommandations</a> quant à l&#8217;implémentation de Web Services conformes aux profils du WS-I.</p><h3><a
name="LagalaxiedesstandardsWebServic"></a>La galaxie des standards Web Services</h3><p>L&#8217;équation de départ se voulait simple :</p><ul><li>Des <strong>standards basés sur XML</strong>, un langage autodescriptif que l&#8217;on présente comme l&#8217;esperanto de l&#8217;informatique <em>(il est compréhensible au-delà des limites technologiques et, pour peu qu&#8217;il soit bien écrit, reste lisible par une personne sans connaissances en programmation)</em>.</li><li>Un triptyque fournissant :<ul><li>Un <strong>protocole d&#8217;échange</strong> : SOAP</li><li>Un <strong>langage de définition d&#8217;interfaces</strong> : WSDL <em>(cet IDL fournit un premier pas vers la description de contrats)</em>.</li><li>Un <strong>modèle d&#8217;annuaire</strong> de services : UDDI <em>(d&#8217;entrée trop complexe, UDDI a rapidement été mis de côté, même s&#8217;il est censé se relever depuis la version 3)</em>.</li></ul></li></ul><p>Mais à peine cette première stack adoptée, elle a montré ses limites et de nouveaux besoins se sont fait sentir engendrant <strong>une armée de standards</strong> <em>(regroupés sous le nom de WS-*)</em>.</p><ul><li>Pour le messaging, avec par exemple, WS-Adressing.</li><li>Pour la gestion des métadonnées. Citons WS-Policy.</li><li>Pour la fiabilisation avec WS-Reliability et WS- Reliable-Messaging.</li><li>Pour la sécurité avec WS-Security et ses add-ons.</li><li>Pour la gestion transactionnelle avec, entre autres, WS-Coordination et WS-Atomic Transaction.</li><li>Pour la gestion des ressources.</li><li>Pour les processus métier avec, par exemple, WS-Choreography Model.</li><li>Pour la gestion avec WS-Management.</li><li>&#8230;</li></ul><p>Ajoutez à cela la dépendance entre ces différents standards, nous obtenons une galaxie plutôt dense de standards ou propositions de standards.</p><div
align="center"> <a
href="http://blog.xebia.fr/wp-content/uploads/2009/02/ws-standards.pdf"><img
src="http://blog.xebia.fr/wp-content/uploads/2009/02/ws-standards.png" alt="ws standards" title="ws standards" width="448" height="318" /></a></div><p>Ces standards sont poussés par une pléthore d&#8217;éditeurs et aboutissent <em>(éventuellement)</em> chez 2 organismes de standardisation : l&#8217;<a
href="http://www.oasis-open.org" title="OASIS" >OASIS</a> et le <a
href="http://www.w3.org/" title="W3C" >W3C</a>.</p><p>Chacun fournissant une <em>(ou plusieurs)</em> implémentation(s) de ces standards, <strong>on aboutit à un modèle qui a peu de chance d&#8217;être interopérable out-of-the-box</strong>.</p><h3><a
name="WebServiceInteroperabilityOrga"></a>Web Service Interoperability Organization (WS-I org)</h3><p>C&#8217;est face à ce constat que s&#8217;est créée la Web Service Interoperability Organization <em>(WS-I org.)</em>.</p><p>Le WS-I est un consortium qui regroupe plus de 160 sociétés. Son objectif annoncé est de faire progresser l&#8217;interopérabilité des Web Services en établissant des bonnes pratiques autour des standards existants. Les travaux du WS-I sont menés en coopération avec les organismes de standardisation OASIS et W3C.</p><p>Le constat de départ du WS-I est simple :</p><ul><li>L&#8217;intérêt des Web Services réside dans <strong>l&#8217;interopérabilité</strong>. C&#8217;est grâce à elle que les Web Services permettront de répondre aux attentes qu&#8217;ils suscitent : <strong>Qualité</strong>, <strong>modularité</strong>, <strong>évolutivité</strong> et surtout <strong>réconciliation de Systèmes Techniques hétérogènes</strong>.</li><li>L&#8217;adoption des Web Services et leur succès sont directement liés aux <strong>technologies qui les supportent</strong>.</li></ul><p>Répondre à ces enjeux permettra :</p><ul><li>De réduire les coûts, la complexité et les risques, notamment en <strong>donnant confiance dans l&#8217;interopérabilité</strong> des Web Service.</li><li>De <strong>faciliter les échanges et la collaboration</strong>, que ce soit au sein de son propre SI ou avec des Systèmes externes.</li></ul><p>Pour arriver à cela, le WS-I élabore et propose trois types de livrables :</p><ul><li>Des <strong>profils</strong> qui regroupent des bonnes pratiques d&#8217;utilisation des standards en vue d&#8217;assurer l&#8217;interopérabilité des implémentations.</li><li>Des <strong>exemples</strong> mettant en œuvre ces profils.</li><li>Des <strong>outils de tests</strong> permettant de vérifier la conformité d&#8217;une implémentation à un ou plusieurs profils.</li></ul><h3><a
name="Lesprofils"></a>Les profils</h3><p>Les profils proposés, même si certains sont encore à l&#8217;état de draft, couvrent aujourd&#8217;hui :</p><ul><li>La couche <strong>transport</strong> avec notamment HTTP, HTTPS, &#8230;</li><li>La couche <strong>invocation</strong> c&#8217;est-à-dire XML, SOAP.</li><li>La couche description de <strong>contrats</strong> avec entre autres XSD et WSDL, &#8230;</li><li>Et aussi les aspects <strong>sécurité</strong> et Reliable messaging.</li></ul><p>Voici comment s&#8217;articulent les différents profils :</p><ul><li>Le <strong>Basic Profile</strong> 1.1 constitue le socle des profils.</li><li>La version 1.2 du Basic Profile, encore à l&#8217;état de DRAFT, l&#8217;étend en y ajoutant notamment le support de WS-Addressing.</li><li>Le <strong>Basic Security Profile</strong> 1.0 y ajoute une dimension sécurité avec la prise en charge de WS-Security 1.0 et de SAML.</li><li>Afin de suivre l&#8217;évolution des standards, un Basic profile 2.0 et un Basic Security Profile 1.1 sont en cours d&#8217;élaboration.</li></ul><div
align="center"> <img
src="http://blog.xebia.fr/wp-content/uploads/2009/02/wsi-profiles.png" alt="wsi profiles" title="wsi profiles" width="700" height="411" /></div><p>L&#8217;objectif à terme est de regrouper l&#8217;ensemble de ces profils au sein d&#8217;un <strong>Reliable Security Profile</strong> 1.0 qui couvrira, en plus de ceux adressés dans le Basic Profile 2.0 et le Basic Security Profile 1.1, les standards WS-Reliable Messaging et WS-Secure Conversation.</p><h3><a
name="Lesoutils"></a>Les outils</h3><p>Le WS-I propose deux outils de tests de conformité : Le Monitor et l&#8217;Analyzer.</p><div
align="center"> <img
src="http://blog.xebia.fr/wp-content/uploads/2009/02/wsi-tools.png" alt="wsi tools" title="wsi tools" width="515" height="570" /></div><ul><li>Le Monitor fonctionne comme un proxy. Il est configuré pour intercepter les requêtes et les réponses échangées entre un client et un Web Service. Ces requêtes et réponses sont tracées dans une base locale.</li><li>L&#8217;Analyzer permet de tester la conformité à un profil. L&#8217;analyse peut porter :</li><ul><li>Sur une définition de contrat <em>(WSDL, XSD)</em>.</li><li>Sur le contenu d&#8217;un annuaire UDDI.</li><li>Sur les traces générées par le monitor.</li></ul></ul><h3><a
name="Perspectives"></a>Perspectives</h3><p>Nous l&#8217;avons vu, le modèle des WS-* a peu de chance d&#8217;être interopérable out of the box. L&#8217;utilisation de SOAP / WSDL à elle seule pose des problèmes d&#8217;interopérabilité.</p><p>L&#8217;<strong>utilisation des outils du WS-I au plus tôt</strong> dans le cycle de développement permet d&#8217;éviter de mauvaises surprises au moment de brancher les systèmes, que l&#8217;on soit dans la position d&#8217;un fournisseur ou d&#8217;un consommateur de services.<br
/> Chacun devrait au minimum utiliser systématiquement l&#8217;Analyzer pour s&#8217;assurer de la conformité des WSDL qu&#8217;il manipule au WS-I Basic Profile. Que l&#8217;on soit dans la position d&#8217;un consommateur ou d&#8217;un fournisseur de service.<br
/> De la même façon, la conformité au Basic Profile des Web Services produits devrait être systématiquement exigée dans un cahier des charges.</p><p>Attention cependant. La conformité aux profils du WS-I, même si elle protège de beaucoup de choses, <strong>ne garantit pas l&#8217;interopérabilité</strong>.</p><p>À noter également que l&#8217;écriture de Web Services en mode <strong>Contract First</strong> et l&#8217;utilisation de <strong>contrats orientés documents</strong> sont deux bonnes pratiques qui permettent, entre autres, d&#8217;écrire des Web Services conformes aux profils du WS-I.</p><div
class="shr-publisher-1499"></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div><div
class='shareaholic-like-buttonset' style='float:none;height:30px;'><a
class='shareaholic-googleplusone' data-shr_size='medium' data-shr_count='true' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2009%2F02%2F18%2Fweb-service-interoperability-ws-i%2F' data-shr_title='Web+Service+Interoperability+%28WS-I%29'></a><a
class='shareaholic-tweetbutton' data-shr_count='horizontal' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2009%2F02%2F18%2Fweb-service-interoperability-ws-i%2F' data-shr_title='Web+Service+Interoperability+%28WS-I%29'></a></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div>]]></content:encoded> <wfw:commentRss>http://blog.xebia.fr/2009/02/18/web-service-interoperability-ws-i/feed/</wfw:commentRss> <slash:comments>5</slash:comments> </item> <item><title>ServiceMix 3.2.x &#8211; Introduction à JBI</title><link>http://blog.xebia.fr/2008/08/01/servicemix-32x-introduction-a-jbi/</link> <comments>http://blog.xebia.fr/2008/08/01/servicemix-32x-introduction-a-jbi/#comments</comments> <pubDate>Fri, 01 Aug 2008 08:18:39 +0000</pubDate> <dc:creator>Manuel Eveno</dc:creator> <category><![CDATA[Java / JEE]]></category> <category><![CDATA[SOA]]></category> <category><![CDATA[ESB]]></category> <category><![CDATA[JBI]]></category> <category><![CDATA[ServiceMix]]></category> <guid
isPermaLink="false">http://blog.xebia.fr/?p=537</guid> <description><![CDATA[Pour bien comprendre le fonctionnement de l&#8217;ESB ServiceMix, il faut tout d&#8217;abord se plonger dans la spécification de Java Business Integration (JBI). Java Business Integration est une norme édictée dans la JSR-208 : basée sur une approche orientée composant, JBI définit la manière de router les messages entre composants. Elle définit les composants et leur [...]]]></description> <content:encoded><![CDATA[<p>Pour bien comprendre le fonctionnement de l&#8217;ESB ServiceMix, il faut tout d&#8217;abord se plonger dans la spécification de Java Business Integration (JBI).</p><p>Java Business Integration est une norme édictée dans la <a
title="JSR-208" href="http://jcp.org/en/jsr/detail?id=208">JSR-208</a> : basée sur une approche orientée composant, JBI définit la manière de router les messages entre composants. Elle définit les composants et leur rôle, les messages qui circulent dans le bus, les canaux de communication entre les composants ainsi que les patterns d&#8217;échange.</p><p>ServiceMix est une implémentation de la norme JBI.</p><h3><a
name="ArchitecturedeJBI"></a>Architecture de JBI</h3><p>Le schéma ci-dessous présente l&#8217;architecture générale de JBI.</p><div
align="center"><img
src="http://blog.xebia.fr/wp-content/uploads/2008/08/architecture-jbi.gif" border="0" alt="" /></div><p>L&#8217;ensemble des éléments de ce schéma sera décrit dans la suite de cet article.</p><h3><a
name="Notiondecomposants"></a>Notion de composants</h3><h4><a
name="Catgoriesdecomposants"></a>Catégories de composants</h4><p>JBI définit deux types de composants : Les Binding Components (BC) et les Service Engines (SE).</p><ul><li> <strong>Les Binding Components (BC)</strong><br
/> Les Binding Components permettent l&#8217;accès depuis l&#8217;extérieur au bus JBI. Ils peuvent à la fois exposer des services ou consommer des services disponibles sur des applications hors de l&#8217;ESB.</li><li> <strong>Les Service Engines (SE)</strong><br
/> Les Services Engines exposent et consomment des services disponibles uniquement à l&#8217;intérieur du bus JBI. Ils ne peuvent accéder au monde extérieur.</li></ul><h4><a
name="LesrlesdescomposantsJBI"></a>Les rôles des composants JBI</h4><p>Un composant JBI peut proposer des services suivant deux types de rôles :</p><ul><li> <strong>Rôle &nbsp;&raquo; Provider &nbsp;&raquo; :</strong><br
/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;Ce rôle est endossable par les Binding Components ou les Service Engines.<br
/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;Un service de type provider fournit des services exposés en interne du bus JBI.<br
/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;Exemples :<br
/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;Un composant de transformation va offrir des services de transformations sur le bus JBI.<br
/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;Un composant Web Service va permettre d&#8217;invoquer un Web Service extérieur à partir du bus JBI.</li><li> <strong>Rôle &nbsp;&raquo; Consumer &nbsp;&raquo; :</strong><br
/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;Ce rôle n&#8217;est endossable que par les Binding Components.<br
/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;Un service de type &nbsp;&raquo; consumer &nbsp;&raquo; écoute les messages provenant de l&#8217;extérieur et initie les échanges JBI à partir des messages qu&#8217;il reçoit.<br
/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;Exemples :<br
/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;Un composant va exposer un Web Service vers l&#8217;extérieur et envoyer chaque message qu&#8217;il reçoit dans le bus JBI.<br
/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;Un composant va attendre des messages sur une file JMS et envoyer chaque message qu&#8217;il reçoit dans le bus JBI.</li></ul><p>Un composant peut fournir à la fois des services <em>consumer</em> et <em>provider</em>.</p><h3><a
name="Lescomposantsconteneursdeservi"></a>Les composants : conteneurs de services</h3><p>Les composants (BC &amp; SE) une fois installés dans le bus JBI proposent des services. Les composants proposent différents services en fonction de leur technologie.</p><p>Exemple : Le composant de type SE servicemix-saxon offre des services de transformation XSL et XQuery, le composant de type BC permet d&#8217;exposer et d&#8217;invoquer des services externes au bus JBI, etc.</p><p>Ces services doivent être en quelque sorte configurés et instanciés pour s&#8217;exécuter. Les composants agissent ainsi comme des conteneurs pour des instances de service.</p><p>Les instances des services sont packagées sous la forme de <em>Service Unit</em> (SU). Ces <em>services units</em> sont ensuite déployés dans le bus JBI qui va installer chaque instance dans le composant (BC ou SE) fournissant le service.</p><p>Les <em>services units</em> doivent être packagés sous la forme de <em>Service Assembly</em> (SA) pour être &laquo;&nbsp;déployable&nbsp;&raquo;.</p><p>JBI définit un packaging standard (une archive Zip) et des descripteurs (fichier jbi.xml) pour l&#8217;installation et le déploiement des composants afin de permettre leur portabilité sur tous les ESB conformes à sa spécification, sans modification. Le package d&#8217;installation contient tout ce qui est nécessaire à l&#8217;installation d&#8217;un composant (librairies &#8230;).</p><h3><a
name="InteractionentrelescomposantsS"></a>Interaction entre les composants ServiceMix</h3><h4><a
name="LeNormalizedMessageRouterNMR"></a>Le Normalized Message Router (NMR)</h4><p>JBI définit un concept de bus interne permettant la communication entre les composants : c&#8217;est le Normalized Message Router (NMR).</p><p>Les éléments qui composent ce NMR sont :</p><ul><li><strong>NormalizedMessage</strong> : Cette interface de la spécification définit la structure standard d&#8217;un message. Ce format est utilisé pour représenter un message en entrée ou en sortie ainsi qu&#8217;un message d&#8217;erreur. Les messages transitent forcément sous la forme de message XML (implémentant l&#8217;interface javax.xml.transform.Source). Un message peut aussi contenir des propriétés et des attachements (binaires ou non).</li><li><strong>MessageExchange</strong> : Cette classe représente un appel transitant à l&#8217;intérieur du bus JBI. L&#8217;échange contient le message d&#8217;entrée, l&#8217;éventuel message de sortie ou d&#8217;erreur (sous la forme de NormalizedMessage) et véhicule aussi les informations de l&#8217;appel (ex : destinataire) et le statut (actif, fini, en erreur). Il existe plusieurs types de MessageExchange, chacun suivant un pattern d&#8217;échange défini dans JBI.</li><li><strong>DeliveryChannel (DC)</strong> : JBI fournit à chaque composant (BC ou SE) un channel d&#8217;échange avec le NMR. Les composants utilisent ce channel pour échanger des messages au travers du NMR.</li></ul><p>L&#8217;implémentation des mécanismes de routage du NMR dépend de chaque solution d&#8217;implémentation de JBI. ServiceMix fournit une implémentation d&#8217;un NMR sous la forme de flow. Il existe trois types de flow dans ServiceMix : Le SedaFlow (défaut), le JMSFlow et la JCAFlow.</p><p>Le SedaFlow stocke les messages en mémoire, le JMSFlow utilise des queues JMS comme implémentation des DeliveryChannel et le JCAFlow se base sur un connecteur JCA pour stocker les messages.</p><h4><a
name="MessageExchangePatternMEP"></a>Message Exchange Pattern (MEP)</h4><p>JBI définit aussi des patterns d&#8217;échanges de message. Chaque composant supporte selon la technologie qu&#8217;il représente tout ou partie de ces patterns d&#8217;échanges.</p><p>Chaque MEP définit l&#8217;enchaînement, le sens et le nombre de messages échangés ainsi que l&#8217;évolution du statut de l&#8217;échange de manière précise.</p><p>Au travers du DeliveryChannel, les composants interagissent avec le NMR de deux façons :</p><ul><li>En acceptant des échanges (MessageExchange) : le composant reçoit un échange émis par un composant.</li><li>En envoyant des échanges (MessageExchange) : le composant initie ou poursuit un échange après avoir traité les messages de l&#8217;échange.</li></ul><p>Un Binding Component de type <em>consumer</em> initie un échange en créant une instance d&#8217;un objet MessageExchange et en le mettant à disposition des autres composants au travers du NMR. Un autre composant va accepter l&#8217;échange, effectuer un traitement puis envoyer l&#8217;échange (éventuellement mis à jour) vers le NMR, etc.</p><p>L&#8217;échange se termine quand l&#8217;un des composants positionne l&#8217;échange au statut &#8216;Done&#8217; ou &#8216;Error&#8217;.</p><p>Les échanges entre les composants sont décrits au travers des patterns suivants. Il existe 4 MEPs différents basés sur les types d&#8217;invocations One-way et Request-Response. Ils permettent de moduler les types de communications entre les composants :</p><ul><li><strong>In-Only (One-Way) :</strong> Le message est envoyé au destinataire. Aucun moyen n&#8217;est mis en œuvre pour s&#8217;assurer qu&#8217;il est bien arrivé ou non.</li><li><strong>Robust In-Only (One-Way) :</strong> Le message est envoyé au destinataire et un message (de type acknowledge) est retransmis à l&#8217;expéditeur en cas d&#8217;erreur.</li><li><strong>In-Out (Request-Response) :</strong> Un message nécessitant une réponse est envoyé au destinataire.</li><li><strong>In Optional-Out (Request-Response) :</strong> Un message est envoyé au destinataire et peut parfois nécessiter une réponse.</li></ul><p>En exemple voici, un échange de type InOut décrit par des diagrammes de séquence UML, le premier finissant normalement, le second finissant en erreur.</p><div
align="center"> <img
src="http://blog.xebia.fr/wp-content/uploads/2008/08/pattern-inout-success.gif" border="0" alt="" /><br
/> <strong>Schéma d&#8217;un échange In Out se terminant normalement</strong><br
/> <br
/>&nbsp;<br
/> <img
src="http://blog.xebia.fr/wp-content/uploads/2008/08/pattern-inout-error.gif" border="0" alt="" /><br
/> <strong>Schéma d&#8217;un échange In Out se terminant en erreur</strong></div><p>Cette présentation de JBI se termine ici, prochainement nous étudierons quelques exemples de mise en œuvre avec ServiceMix.</p><div
class="shr-publisher-537"></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div><div
class='shareaholic-like-buttonset' style='float:none;height:30px;'><a
class='shareaholic-googleplusone' data-shr_size='medium' data-shr_count='true' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2008%2F08%2F01%2Fservicemix-32x-introduction-a-jbi%2F' data-shr_title='ServiceMix+3.2.x+-+Introduction+%C3%A0+JBI'></a><a
class='shareaholic-tweetbutton' data-shr_count='horizontal' data-shr_href='http%3A%2F%2Fblog.xebia.fr%2F2008%2F08%2F01%2Fservicemix-32x-introduction-a-jbi%2F' data-shr_title='ServiceMix+3.2.x+-+Introduction+%C3%A0+JBI'></a></div><div
style="clear: both; min-height: 1px; height: 3px; width: 100%;"></div>]]></content:encoded> <wfw:commentRss>http://blog.xebia.fr/2008/08/01/servicemix-32x-introduction-a-jbi/feed/</wfw:commentRss> <slash:comments>2</slash:comments> </item> </channel> </rss>
