<?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/"
	>

<channel>
	<title>OCTO talks ! &#187; Java</title>
	<atom:link href="http://blog.octo.com/tag/java/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.octo.com</link>
	<description>Le blog d&#039;OCTO Technology, cabinet d&#039;architectes en systèmes d&#039;information</description>
	<lastBuildDate>Fri, 03 Feb 2012 13:46:10 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Thrift et Protocol Buffers : compacité du message sérialisé dans le monde Java</title>
		<link>http://blog.octo.com/thrift-protobuf-compacite/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=thrift-protobuf-compacite</link>
		<comments>http://blog.octo.com/thrift-protobuf-compacite/#comments</comments>
		<pubDate>Fri, 27 Jan 2012 10:15:49 +0000</pubDate>
		<dc:creator>Borémi Toch</dc:creator>
				<category><![CDATA[Architecture et technologies]]></category>
		<category><![CDATA[développement]]></category>
		<category><![CDATA[IDL]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[protobuf]]></category>
		<category><![CDATA[sérialisation]]></category>
		<category><![CDATA[Thrift]]></category>

		<guid isPermaLink="false">http://blog.octo.com/?p=28819</guid>
		<description><![CDATA[Un précédent article a exposé les grands principes de la sérialisation avec Thrift et Procotol Buffers. Ces deux frameworks promettent notamment une représentation des messages optimisée en termes de taille, ce qui est avéré dans le benchmark JVM Serializers : Thrift et Protocol Buffers y obtiennent une réduction de taille du message de 73% par [...]
Suggestion d'articles :<ol>
<li><a href='http://blog.octo.com/serialisation-thrift-et-protocol-buffers/' rel='bookmark' title='Sérialisation : Thrift et Protocol Buffers, principes et aperçu'>Sérialisation : Thrift et Protocol Buffers, principes et aperçu</a></li>
<li><a href='http://blog.octo.com/socle-technique-des-applications-java-ee-dans-le-war-ou-dans-le-serveur/' rel='bookmark' title='Socle technique des applications Java EE : dans le WAR ou dans le serveur ?'>Socle technique des applications Java EE : dans le WAR ou dans le serveur ?</a></li>
<li><a href='http://blog.octo.com/les-nouveautes-du-langage-dans-java-7/' rel='bookmark' title='Les nouveautés du langage dans Java 7'>Les nouveautés du langage dans Java 7</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[
<div class="topsy_widget_data topsy_theme_blue" style="float: right;margin-left: 0.75em; background: url(data:,%7B%20%22url%22%3A%20%22http%253A%252F%252Fblog.octo.com%252Fthrift-protobuf-compacite%252F%22%2C%20%22shorturl%22%3A%20%22http%3A%2F%2Fbit.ly%2FxOyAR8%22%2C%20%22style%22%3A%20%22small%22%2C%20%22title%22%3A%20%22Thrift%20et%20Protocol%20Buffers%20%3A%20compacit%C3%A9%20du%20message%20s%C3%A9rialis%C3%A9%20dans%20le%20monde%20Java%22%20%7D);"></div>
<p><a href="http://blog.octo.com/serialisation-thrift-et-protocol-buffers/">Un précédent article</a> a exposé les grands principes de la sérialisation avec <a href="http://thrift.apache.org/">Thrift</a> et <a href="http://code.google.com/p/protobuf/">Procotol Buffers</a>. Ces deux frameworks promettent notamment une <strong>représentation des messages optimisée en termes de taille</strong>, ce qui est avéré dans le benchmark <a href="https://github.com/eishay/jvm-serializers/wiki/">JVM Serializers</a> : Thrift et Protocol Buffers y obtiennent une réduction de taille du message de 73% par rapport à la sérialisation native Java. Ce benchmark regroupe par ailleurs de nombreux autres frameworks de sérialisation du monde Java, mais se limite toutefois à l&#8217;utilisation d&#8217;un <a href="https://github.com/eishay/jvm-serializers/wiki/TestValue">unique message de test</a>. </p>
<p>Le présent article analyse l&#8217;<strong>influence de la structure</strong> (nombre et taille des objets, complexité de la grappe) <strong>sur la compacité du message sérialisé pour Thrift et Protocol Buffers</strong>. La comparaison est réalisée en Java, son protocole de sérialisation standard servant de référence.<br />
<span id="more-28819"></span></p>
<h2>Conditions du test</h2>
<p>Afin d&#8217;évaluer diverses structures de messages, le prototype utilise une <a href="http://fr.wikipedia.org/wiki/Arbre_enracin%C3%A9">structure arborescente</a>. Traditionnellement, ce type de structure est récursif. Cependant, il n&#8217;est pas compatible avec la limitation de Thrift sur la <a href="http://fr.wikipedia.org/wiki/D%C3%A9claration_avanc%C3%A9e">déclaration avancée</a> abordée <a href="http://blog.octo.com/serialisation-thrift-et-protocol-buffers/#recursion">dans le précédent article</a>.<br />
La profondeur a donc été arbitrairement limitée au niveau 6, soit 127 nœuds au maximum pour un arbre binaire complet. Il y a un type différent par profondeur, de Node0 pour la racine à Node6 pour les feuilles les plus basses. Les arbres générés le sont selon <strong>trois paramètres</strong> :</p>
<ul>
<li><strong>le nombre total de nœuds</strong>, qui permet de faire varier le nombre d&#8217;objets du message,</li>
<li><strong>la cardinalité des fratries </strong>, qui joue sur la complexité : plus cette cardinalité est faible pour un nombre de nœuds donné, plus les fratries sont petites et nombreuses, donc plus le message est complexe,</li>
<li>et <strong>la taille des nœuds</strong>, qui est fonction du champ &laquo;&nbsp;description&nbsp;&raquo;. Son contenu est une chaîne de caractères différente pour chacun d&#8217;eux et générée par décalage des valeurs <a href="http://fr.wikipedia.org/wiki/Unicode">Unicode</a> des caractères.</li>
</ul>
<p>La construction des arbres se fait récursivement et équitablement entre les fils d&#8217;un nœud. Ci-dessous trois exemples d&#8217;arbre à 5 nœuds avec, de gauche à droite, des tailles de fratries de 1, 2 et 3. Les numéros sont présents à titre indicatif et indiquent l&#8217;ordre de création des nœuds par l&#8217;algorithme de construction.<br />
<a href="http://blog.octo.com/wp-content/uploads/2012/01/5nodeN-Tree_Colours.png"><img src="http://blog.octo.com/wp-content/uploads/2012/01/5nodeN-Tree_Colours.png" alt="" title="5nodeN-Tree_Colours" width="500" height="183" class="aligncenter size-full wp-image-29188" /></a></p>
<p>Les déclarations dans les IDLs Thrift IDL et Protocol Buffers language sont disponibles <a href="#annexe">en fin d&#8217;article</a>. Les versions utilisées sont 0.8.0 pour Thrift, 2.4.1 pour Protocol Buffers et HotSpot 1.6.0_29 pour la JVM.</p>
<h2>Impact du nombre d&#8217;objets du message</h2>
<p>Dans un premier temps, la complexité est fixée au minimum : </p>
<ul>
<li>La longueur des descriptions de chaque nœud est constante (32 caractères),</li>
<li>le nombre de nœuds est variable,</li>
<li>la structure choisie est le 1024-tree qui équivaut à un arbre à deux niveaux dans cette étude.</li>
</ul>
<p>En effet, si la cardinalité des fratries est supérieure au nombre de nœuds n, on obtient un arbre à deux niveaux, une racine Node0 et n-1 enfants Node1. Les 1024-trees de cet article ont tous cette structure car n est toujours inférieur à 1024.<br />
<img src="http://blog.octo.com/wp-content/uploads/2012/01/nnode1024-tree.png" alt="" title="nnode1024-tree" width="498" height="177" class="aligncenter size-full wp-image-29200" /></p>
<p>Tracer la taille du message sérialisé en fonction du nombre de nœuds donne le graphe suivant :<br />
<img class="aligncenter size-full wp-image-28852" title="List_ByteSizeVsNodeCount" src="http://blog.octo.com/wp-content/uploads/2012/01/List_ByteSizeVsNodeCount.png" alt="" width="500" height="362" /><br />
Aussi bien sur cet histogramme que sur les suivants, une <strong>barre plus basse</strong> correspond systématiquement à un <strong>meilleur résultat</strong> et l&#8217;ordre des barres (de gauche à droite) correspond à celui de la légende (de haut en bas).<br />
Sur ce premier graphique, on retrouve un constat du benchmark Java Serializers, mais dans un contexte de message plus complexe : <strong>Thrift et protobuf ont des performances très proches</strong>.</p>
<p>Le graphique ci-dessous rapporte leurs résultats à ceux de la sérialisation Java. On constate que <strong>leur avantage en termes de taille de message s&#8217;amenuise à mesure que l&#8217;arbre grossit</strong>.<br />
<img class="aligncenter size-full wp-image-28853" title="List_RelativeSizeVsNodeCount" src="http://blog.octo.com/wp-content/uploads/2012/01/List_RelativeSizeVsNodeCount.png" alt="" width="500" height="380" /></p>
<p>Sur le graphique suivant, on observe que la taille moyenne d&#8217;un nœud décroît rapidement pour la sérialisation Java. En effet, le <a href="http://docs.oracle.com/javase/7/docs/platform/serialization/spec/protocol.html">protocole de sérialisation Java</a> ajoute aux informations du message lui-même la description des classes sérialisées. Ce surcoût, important pour un petit message, devient négligeable pour des messages constitués de nombreux objets du même type.<br />
<img class="aligncenter size-full wp-image-28857" title="List_avgNodeSize" src="http://blog.octo.com/wp-content/uploads/2012/01/List_avgNodeSize.png" alt="" width="500" height="360" /><br />
Les protocoles de protobuf et Thrift, quant à eux, contiennent très peu d&#8217;information de structure : uniquement un identifiant de champ et un type. Ainsi ils voient la taille moyenne d&#8217;un nœud croître légèrement, car les listes d&#8217;enfants augmentent en nombre et taille quand l&#8217;arbre grossit.</p>
<h2>Impact de la taille des objets</h2>
<p>Pour ce second test, on fige la structure du message pour mesurer l&#8217;influence de la quantité d&#8217;information contenue dans chaque nœud :</p>
<ul>
<li>Un 1024-tree est considéré comme dans le test précédent,</li>
<li>sa taille est fixée à 31 nœuds,</li>
<li>la taille du champ &laquo;&nbsp;description&nbsp;&raquo; est utilisé comme variable.</li>
</ul>
<p><img class="aligncenter size-full wp-image-28859" title="Desc_ByteSizeVsDescLength" src="http://blog.octo.com/wp-content/uploads/2012/01/Desc_ByteSizeVsDescLength.png" alt="" width="500" height="371" /><br />
Les résultats concernant la taille du message sont similaires au test précédent, Thrift et protobuf sont très proches et font mieux que la sérialisation Java surtout pour de petits objets.<br />
<img src="http://blog.octo.com/wp-content/uploads/2012/01/Desc_SizeDifferenceVsDescLength2.png" alt="" title="Desc_SizeDifferenceVsDescLength" width="500" height="284" class="aligncenter size-full wp-image-28867" /><br />
Figer la structure du message montre que la différence de taille par rapport au protocole de sérialisation Java est quasi-constante. Ceci est dû au fait que <strong>protobuf et Thrift n&#8217;apportent aucun gain notable lorsqu&#8217;on fait varier la taille de la chaîne de caractères</strong>.<br />
En effet, les trois protocoles en jeu la sérialisent sous forme de chaîne en UTF8 précédée de sa longueur. La différence est que le protocole Java utilise 2 octets pour la longueur des chaînes de moins de 2^16 caractères, tandis que les deux frameworks ont recours à un <a href="http://code.google.com/apis/protocolbuffers/docs/encoding.html#varints">varint</a>. Le saut entre 64 et 128 caractères est dû au fait que le format varint n&#8217;utilise qu&#8217;un octet pour coder les entiers entre 0 et 127, puis deux de 128 à 2^14.</p>
<h2>Impact de la structure du message</h2>
<p>Pour évaluer l&#8217;influence de la structure du message :</p>
<ul>
<li>la description de chaque nœud est fixée à 32 caractères,</li>
<li>le nombre de nœuds est variable,</li>
<li>la cardinalité des fratries prend trois valeurs : 2, 4 et 1024.</li>
</ul>
<p>Par exemple, voici les trois variations considérées de l&#8217;arbre à 7 nœuds :<br />
<a href="http://blog.octo.com/wp-content/uploads/2012/01/7node241024-Trees.png"><img src="http://blog.octo.com/wp-content/uploads/2012/01/7node241024-Trees.png" alt="" title="7node241024-Trees" width="500" height="105" class="aligncenter size-full wp-image-29205" /></a></p>
<p>Le graphique qui suit recense les tailles des messages sérialisés.<br />
<img src="http://blog.octo.com/wp-content/uploads/2012/01/Tree_ByteSizeVsNodeCount.png" alt="" title="Tree_ByteSizeVsNodeCount" width="500" height="321" class="aligncenter size-full wp-image-28871" /><br />
Pour tous les protocoles de sérialisation, le comportement est similaire : <strong>plus de complexité conduit à un message sérialisé moins compact</strong>.<br />
Cela est dû au fait que plus de complexité se traduit par un plus grand nombre de listes de noeuds-enfants. Cependant, <strong>la variation reste négligeable (environ 1%) pour Thrift et protobuf</strong>. </p>
<p>Le protocole de sérialisation Java est lui plus fortement influencé (jusqu&#8217;à 13%). En effet la quantité d&#8217;information utilisée par les descripteurs de classes est liée au nombre de types de classes mises en jeu. Plus les fratries sont grandes, moins on utilise de classes différentes. Par exemple, pour 63 nœuds, le 2-tree utilise toutes les classes de Node0 à Node5, le 4-tree s&#8217;arrête à Node3, et le 1024-tree à Node1.<br />
Le résultat particulièrement bon du 2-tree de taille 127 est lié au fait que Node6 n&#8217;a pas de liste d&#8217;enfants et est donc plus compact que les autres types de Nodes. Dans cet arbre, la majorité des nœuds (64) est de type Node6.  </p>
<p>Les tailles moyennes par nœud sont représentées dans l&#8217;histogramme ci-dessous :<br />
<img src="http://blog.octo.com/wp-content/uploads/2012/01/Tree_AvgNodeSizeVsNodeCount.png" alt="" title="Tree_AvgNodeSizeVsNodeCount" width="500" height="334" class="aligncenter size-full wp-image-28873" /><br />
L&#8217;évolution est conforme aux observations du premier test : <strong>l&#8217;écart entre Java et les deux frameworks s&#8217;amenuise lorsqu&#8217;on augmente la taille du graphe</strong> sans pour autant être négligeable.</p>
<p>En traçant le gain apporté par les deux frameworks par rapport à la sérialisation Java on obtient :<br />
<img src="http://blog.octo.com/wp-content/uploads/2012/01/Tree_RelativeSizeVsNodeCount1.png" alt="" title="Tree_RelativeSizeVsNodeCount" width="500" height="320" class="aligncenter size-full wp-image-28874" /></p>
<p>Par exemple, en considérant le message du 4-tree à 63 nœuds et un système devant soutenir une charge de 10000 requêtes/s, le remplacement de la sérialisation Java par Thrift permet de diminuer le besoin de bande passante de 75.45 Mo/s à 40.68Mo/s, soit un gain de 46%.</p>
<h2>Conclusion</h2>
<p>Cet article a présenté une comparaison portant sur la taille de sérialisation avec des messages complexes. Par rapport au benchmark JVM-serializers, l&#8217;avantage de Thrift et protobuf sur la sérialisation native Java est moins décisif en termes de compacité, même s&#8217;il reste intéressant.</p>
<p><strong>La taille du message sérialisé par Thrift ou Protocol Buffers n&#8217;est pas influencée par la structure même du message. C&#8217;est surtout son volume qui a un impact</strong> : les deux frameworks offrent une sérialisation bien plus compacte que celle de Java surtout sur de petits messages. Cette observation rejoint le fait que Protocol Buffers n&#8217;est <a href="http://code.google.com/apis/protocolbuffers/docs/techniques.html#large-data">pas particulièrement adapté aux volumes de données importants</a>.</p>
<p>Il faut rappeler qu&#8217;employer la sérialisation native Java comme référence n&#8217;est légitime que parce que cet article se limite aux protocoles de sérialisation.  Thrift et Protocol Buffers offrent d&#8217;autres avantages tels l&#8217;interopérabilité avec plusieurs langages et la compatibilité ascendante et descendante des messages. Ils sont abordés dans l&#8217;<a href="http://blog.octo.com/serialisation-thrift-et-protocol-buffers/">article précédent</a>. </p>
<p>Pour aller plus loin, on pourrait analyser les temps de sérialisation, l&#8217;empreinte mémoire, l&#8217;intégration aux processus de build&#8230;</p>
<h3 id="annexe">Annexes</h3>
<p>Voici la déclaration des objets en <strong>Thrift IDL</strong> : tree.thrift</p>
<pre class="brush:plain ; collapse: false">namespace java com.octo.example.serialization.model.thrift

enum RoomType {
        SINGLE =0,
        DOUBLE =1,
        SUITE =2
}
struct Node6 {
    1: optional i32 number,
    2: optional bool even,
    3: optional double rate,
    4: optional RoomType type,
    5: optional string description,
}
struct Node5 {
    1: optional i32 number,
    2: optional bool even,
    3: optional double rate,
    4: optional RoomType type,
    5: optional string description,
    6: list children,
}
[...]</pre>
<p>et ainsi de suite jusqu&#8217;au Node0, qui correspond la racine de l&#8217;arbre. L&#8217;ordre employé évite le recours à la déclaration avancée.</p>
<p>Ci-dessous, l&#8217;équivalent en <strong>Protocol Buffers language</strong> : tree.proto</p>
<pre class="brush:plain ; collapse: false">package serialization;

option java_package = "com.octo.example.serialization.model";
option java_outer_classname = "LimitedTreeProto";

enum RoomType {
    SINGLE =0;
    DOUBLE =1;
    SUITE =2;
}
message Node0 {
    optional int32 number =1;
    optional bool even =2;
    optional double rate =3;
    optional RoomType type =4;
    optional string description = 5;
    repeated Node1 children = 6;
}
[...]
message Node6 {
    optional int32 number =1;
    optional bool even =2;
    optional double rate =3;
    optional RoomType type =4;
    optional string description = 5;
}</pre>
<p>L&#8217;ordre des nœuds plus naturel est supporté par le compilateur Protobuf.</p>

 <img src="http://blog.octo.com/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=28819" width="1" height="1" style="display: none;" /><p>Suggestion d'articles :</p><ol>
<li><a href='http://blog.octo.com/serialisation-thrift-et-protocol-buffers/' rel='bookmark' title='Sérialisation : Thrift et Protocol Buffers, principes et aperçu'>Sérialisation : Thrift et Protocol Buffers, principes et aperçu</a></li>
<li><a href='http://blog.octo.com/socle-technique-des-applications-java-ee-dans-le-war-ou-dans-le-serveur/' rel='bookmark' title='Socle technique des applications Java EE : dans le WAR ou dans le serveur ?'>Socle technique des applications Java EE : dans le WAR ou dans le serveur ?</a></li>
<li><a href='http://blog.octo.com/les-nouveautes-du-langage-dans-java-7/' rel='bookmark' title='Les nouveautés du langage dans Java 7'>Les nouveautés du langage dans Java 7</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://blog.octo.com/thrift-protobuf-compacite/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>GWT et sécurité, se prémunir des CSRF</title>
		<link>http://blog.octo.com/gwt-et-securite-se-premunir-des-csrf/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=gwt-et-securite-se-premunir-des-csrf</link>
		<comments>http://blog.octo.com/gwt-et-securite-se-premunir-des-csrf/#comments</comments>
		<pubDate>Fri, 09 Dec 2011 12:53:45 +0000</pubDate>
		<dc:creator>Mathieu Lorber</dc:creator>
				<category><![CDATA[Architecture et technologies]]></category>
		<category><![CDATA[CSRF]]></category>
		<category><![CDATA[GWT]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[RIA]]></category>
		<category><![CDATA[sécurité]]></category>

		<guid isPermaLink="false">http://blog.octo.com/?p=27763</guid>
		<description><![CDATA[Préambule Les applications Web enrichies, utilisant JavaScript pour mettre à jour tout ou partie d’une page web, sont officiellement nées en 2005 avec l’apparition du terme Ajax, et sont aujourd’hui communes. De ce concept sont ensuite nées les applications JavaScript « Single Page Interface », modèle dans lequel rentre l’application typique GWT. Le framework propose [...]
Suggestion d'articles :<ol>
<li><a href='http://blog.octo.com/initiation-a-la-securite-des-web-services/' rel='bookmark' title='Initiation à la sécurité des Web Services'>Initiation à la sécurité des Web Services</a></li>
<li><a href='http://blog.octo.com/securite-des-services-web-1ere-partie/' rel='bookmark' title='Sécurité des services web – 1ère partie'>Sécurité des services web – 1ère partie</a></li>
<li><a href='http://blog.octo.com/html5-offline-et-securite/' rel='bookmark' title='HTML5, offline et sécurité'>HTML5, offline et sécurité</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[
<div class="topsy_widget_data topsy_theme_blue" style="float: right;margin-left: 0.75em; background: url(data:,%7B%20%22url%22%3A%20%22http%253A%252F%252Fblog.octo.com%252Fgwt-et-securite-se-premunir-des-csrf%252F%22%2C%20%22style%22%3A%20%22small%22%2C%20%22title%22%3A%20%22GWT%20et%20s%C3%A9curit%C3%A9%2C%20se%20pr%C3%A9munir%20des%20CSRF%22%20%7D);"></div>
<h2>Préambule</h2>
<p>Les applications Web enrichies, utilisant JavaScript pour mettre à jour tout ou partie d’une page web, sont officiellement nées en 2005 avec l’apparition du terme Ajax, et sont aujourd’hui communes. De ce concept sont ensuite nées les applications JavaScript « Single Page Interface », modèle dans lequel rentre l’application typique GWT. Le framework propose aujourd’hui un modèle de programmation au juste milieu entre les paradigmes du développement RDA (pour <a title="Rich Desktop Application sur Wikipedia" href="http://fr.wikipedia.org/wiki/Rich_Desktop_Application" target="_blank">Rich Desktop Application</a>) et du développement Web. Après compilation, une application GWT devient une application JavaScript tout à fait standard du point du vue du browser.</p>
<p>Les applications Ajax n’introduisent pas de <em>nouvelles</em> failles de sécurité. Techniquement, les risques et les techniques d’exploitation sont les mêmes. Si certaines failles sont affaiblies par le modèle, d’autres ont vu leur terrain de jeu évoluer.</p>
<p>Le but de cet article et d&#8217;un autre à venir est de rappeler les failles de sécurité qui concernent tout particulièrement la portion JavaScript – et donc GWT – de nos applications Web, puis de présenter les réponses qu’il convient de mettre en œuvre dans une application GWT pour contrecarrer les éventuelles attaques.</p>
<p><span id="more-27763"></span></p>
<p>En point de départ, nous nous appuierons sur l’<a title="Site officiel de l'OWASP" href="https://www.owasp.org/" target="_blank">OWASP</a> &amp; son <a title="OWASP Top 10 2010 des failles des applications Web" href="https://www.owasp.org/index.php/Top_10_2010" target="_blank">top ten 2010</a> des failles de sécurité des applications Web :</p>
<ol>
<li><a title="Top 10 2010-A1" href="https://www.owasp.org/index.php/Top_10_2010-A1" target="_blank">Injection</a></li>
<li><a title="Top 10 2010-A2" href="https://www.owasp.org/index.php/Top_10_2010-A2" target="_blank">Cross-Site Scripting (XSS)</a></li>
<li><a title="Top 10 2010-A3" href="https://www.owasp.org/index.php/Top_10_2010-A3" target="_blank">Broken Authentication and Session Management</a></li>
<li><a title="Top 10 2010-A4" href="https://www.owasp.org/index.php/Top_10_2010-A4" target="_blank">Insecure Direct Object References</a></li>
<li><a title="Top 10 2010-A5" href="https://www.owasp.org/index.php/Top_10_2010-A5" target="_blank">Cross-Site Request Forgery (CSRF)</a></li>
<li><a title="Top 10 2010-A6" href="https://www.owasp.org/index.php/Top_10_2010-A6" target="_blank">Security Misconfiguration</a></li>
<li><a title="Top 10 2010-A7" href="https://www.owasp.org/index.php/Top_10_2010-A7" target="_blank">Insecure Cryptographic Storage</a></li>
<li><a title="Top 10 2010-A8" href="https://www.owasp.org/index.php/Top_10_2010-A8" target="_blank">Failure to Restrict URL Access</a></li>
<li><a title="Top 10 2010-A9" href="https://www.owasp.org/index.php/Top_10_2010-A9" target="_blank">Insufficient Transport Layer Protection</a></li>
<li><a title="Top 10 2010-A10" href="https://www.owasp.org/index.php/Top_10_2010-A10" target="_blank">Unvalidated Redirects and Forwards</a></li>
</ol>
<p>Deux de ces failles potentielles nous concernent tout particulièrement dans une couche Ajax : les failles XSS [2] et CSRF [5]. Elles auront dans ce contexte la particularité sympathique de rendre l&#8217;application vulnérable quelles que soient les protections mises en place uniquement côté serveur. Leur compréhension et la connaissance des mécanismes de protection par le développeur sont donc essentielles. Dans ce premier article, nous nous focaliserons sur les attaques de type CSRF.</p>
<p>A l&#8217;écriture de ces lignes, la version courante de GWT est la 2.4.</p>
<h2>CSRF : Cross Site Request Forgery</h2>
<p><em>Traduire avec élégance par &laquo;&nbsp;falsification de requête inter-site&nbsp;&raquo;.</em></p>
<p>Une attaque CSRF consiste à utiliser les autorisations qu’a un utilisateur sur un site donné contre son gré. Il s’agit de construire sur un domaine sous le contrôle de l’attaquant une requête vers le site attaqué ; la requête sera soumise par le browser de l’utilisateur victime, et exécutée avec les droits de ce dernier. Si le cookie permet de s’assurer que la requête provient du browser du bon utilisateur, il ne permet pas de vérifier que l’appel provient du bon site&#8230;</p>
<h3>La same origin policy</h3>
<p>Petit rappel des règles du jeu. Tout browser se doit de restreindre les capacités de JavaScript à la same origin policy. Cette règle rend impossible un appel asynchrone via XMLHttpRequest sur un autre domaine. Toute manipulation du DOM est aussi restreinte : une iframe ayant pour source une page sur un autre domaine ne sera ni lisible ni pilotable par un script de la page parente.</p>
<p>Il s’agit bien d’empêcher la lecture d’une requête provenant d’un autre domaine : initier la requête est possible (et heureusement), pas <em>traiter</em> son résultat. C’est sur cet état de fait que s’appuient les attaques CSRF.</p>
<h3>Une attaque CSRF typique : c’est l’histoire d’un steak</h3>
<p>Plantons le décor. Ghislain est boucher, sur son site <em>myboucher.com</em>, il vend des bavettes. Georges, qui possède une brasserie, est son premier client. Richard est boucher lui aussi, mais jalouse Ghislain. A ses heures perdues, il lit des articles underground de l’internet mondial. Et agit secrètement sur <em>iamthevilain.com</em>.</p>
<p>Voici l&#8217;histoire de son attaque contre le site de Ghislain. Georges est sa première victime.</p>
<p><a href="http://blog.octo.com/wp-content/uploads/2011/12/csrf-big.jpg" rel="lightbox"><img title="CSRF" src="http://blog.octo.com/wp-content/uploads/2011/11/csrf.jpg" alt="Le scénario d'une attaque CSRF" width="600" height="292" /></a></p>
<ol>
<li>Georges se connecte sur <em>myboucher.com</em>. Il s’authentifie : login/mot de passe, qui ne seront pas divulgués dans cet article. Son browser reçoit alors un cookie de session ; ce dernier sera systématiquement envoyé par toute requête sur myboucher.com</li>
<li>Ce qu’il a fait sur <em>myboucher.com</em> précisément ne nous regarde pas, mais il ne s&#8217;est pas déconnecté. Plus tard, du fait d&#8217;un mail d&#8217;origine inconnue, il atterri sur la page <em>http://iamthevilain.com/hack-myboucher.action</em> . Sur cette page se trouve un formulaire qui correspond très précisément à celui qui est existe sur <em>myboucher.com</em> pour supprimer l&#8217;intégralité des informations du compte de l&#8217;utilisateur courant. Les champs sont identiques, et l&#8217;attribut HTML <em>action</em> du formulaire pointe sur la page correspondant à la suppression sur <em>myboucher.com</em>. Le formulaire est placé dans une frame invisible.</li>
<li>Un code JavaScript soumet automatiquement le formulaire, en JavaScript, sans que Georges ne fasse quoi que ce soit. Une requête POST parfaitement valide, ordonnant une suppression de compte est alors soumise à <em>myboucher.com</em>, avec le cookie qui authentifie Georges. Notre brasseur n’a plus de compte, et du fait de la frame, il ne s’est aperçu de rien.<br />
Ghislain perd bon nombre de ses comptes utilisateurs, sans pouvoir fournir à ces derniers la moindre explication.</li>
</ol>
<p>Il est à noter que l’attaque CSRF n’a de sens que sur des utilisateurs connectés avec des droits spécifiques (dans 99,72% des cas). D&#8217;ailleurs, elle est d’autant plus dévastatrice que la victime a de droits sur le site. L’ensemble des protections est basé sur le fait que la victime potentielle dispose d’une session sur le serveur.</p>
<h3>CSRF &amp; HTTP</h3>
<p>Dans le scenario ci-dessus, j’ai volontairement pris l’exemple d’une action nécessitant une requête POST. L’attaque CSRF la plus basique se base sur une requête GET. En effet, pour faire une requête GET sur un autre domaine sans que l’utilisateur ne puisse s’en apercevoir, il suffit d’utiliser une frame, une image… C&#8217;est possible dans un simple mail !</p>
<p>Sauf qu&#8217;une telle attaque CSRF ne devrait pas avoir de sens : une action d’<em>écriture</em> ne devrait jamais être faite via une requête GET. Une requête GET doit toujours pouvoir être exécutée sans mettre en question l’intégrité de vos données. C’est un des principes de HTTP (cf. la <a title="RFC HTTP au sujet des requêtes GET" href="http://tools.ietf.org/html/rfc2616#section-9.1.1" target="_blank">RFC</a>), sur lequel est basée la conception des moteurs de recherche, des browsers, etc… Par exemple, un browser aura le droit de précharger les ressources trouvées en lien sur une page : imaginez les dégâts d’un simple lien &laquo;&nbsp;supprimer mon compte&nbsp;&raquo;. Derrière ce lien devrait en fait se cacher un formulaire HTML et une requête POST. Pour cette raison, ce sont uniquement les requêtes POST que nous voudrons protéger.</p>
<h3>Utiliser le referer ? Non</h3>
<p>Dans la définition d&#8217;HTTP se trouve un champ de header destiné à contenir l&#8217;URL de la page qui a initié la requête pour le browser, il s&#8217;agit du referer. C&#8217;est ce champ qui permet par exemple aux outils de statistiques de dire d&#8217;où vient un visiteur. On pourrait dès lors vouloir s&#8217;appuyer sur ce champ pour se prémunir des CSRF. Lors d&#8217;une soumission de formulaire depuis un site étranger, le referer devrait <em>normalement</em> contenir l&#8217;url de la page dans laquelle se trouvait le formulaire initial. C&#8217;est ce &laquo;&nbsp;<em>normalement</em>&nbsp;&raquo; qui nous arrêtera là. Dans la pratique, le referer ne sera pas toujours alimenté, de plus, certaines versions d&#8217;Internet Explorer et du player Flash contiennent des failles permettant la construction d&#8217;attaque CSRF avec manipulation des headers.</p>
<h3>Les techniques de protection.</h3>
<p>Dans une application WEB standard, les requêtes POST sont soumises par les formulaires, et la protection aux CSRF passe par l’utilisation d’un jeton. Ce dernier est généré de façon non prédictive côté serveur, et conservé dans la session utilisateur (ou directement construit à partir de l’identifiant de session, typiquement un hash). Il est donc associé à une session donnée. Lors de la construction d&#8217;un formulaire dans une page HTML, toujours côté serveur, il est injecté dans un champ caché (<em>&lt;input type=&nbsp;&raquo;hidden&nbsp;&raquo; &#8230; /&gt;</em>). Sa présence est vérifiée à la soumission du formulaire. Du fait de la same origin policy, il est impossible à l&#8217;attaquant potentiel de récupérer un jeton. Il ne peut dès lors plus construire un formulaire contenant un jeton valide pour une quelconque session existante.</p>
<p>Les applications Ajax utilisent l&#8217;objet XMLHttpRequest pour faire des appels HTTP sans recharger la page web, et traiter le résultat de façon asynchrone. Si elles ne sont pas faites de la même façon, il s&#8217;agit des mêmes requêtes POST que celles des formulaires. La technique de protection sera la même, et il faudra utiliser un jeton conservé en session. XMLHttpRequest permettant la manipulation des headers HTTP, cette capacité sera souvent utilisée pour glisser le jeton dans un header dédié et ne pas polluer le corps de requête.</p>
<p>La plupart des frameworks web classique récents (Rails, Django, Symfony, ASP.NET MVC, ou encore Seam dans le monde Java, dont les frameworks sont plus globalement de mauvais élèves) proposent une solution de jeton intégrée aux formulaires, plus ou moins transparente pour le développeur. A contrario, les frameworks JavaScript, s’ils simplifient généralement les opérations de requêtes asynchrones, n’apportent pas de solution prémâchée. « Normal », puisque cette intégration passe aussi par l’implémentation côté serveur. A noter le cas de Rails, qui intègre nativement une protection pour la partie Javascript : le token est fourni via une balise dans le HTML, et l&#8217;objet JavaScript XMLHttpRequest est enrichi par le framework pour que le token soit systématiquement glissé dans les headers HTTP. Comme pour un formulaire standard, l&#8217;ensemble est totalement transparent pour le développeur !</p>
<p>GWT dans cet environnement a un côté vicieux. Le développeur GWT écrit bien souvent des requêtes RPC, et &laquo;&nbsp;ignore&nbsp;&raquo; le fait que ces requêtes sont techniquement des requêtes POST tout à fait standards, utilisant l&#8217;objet XMLHttpRequest. On pourra d&#8217;ailleurs faire un rapide aparté sur les applications basée sur Flash, et donc Flex, qui utilisent les mêmes requêtes, sans que les frameworks communément utilisés ne poussent de solution intégrée.</p>
<h3>Que faire avec GWT ?</h3>
<h4>GWT-RPC</h4>
<p>Il convient tout d’abord de souligner que GWT propose nativement une première ligne de défense en RPC. Le nom d&#8217;un des fichiers chargés par le bootstrap interne GWT (pour être plus précis, le nom de la permutation correspondante dans le mécanisme de <a title="Deferred Binding" href="http://code.google.com/webtoolkit/doc/latest/DevGuideCodingBasics.html#DevGuideDeferredBinding" target="_blank">Deferred Binding</a> du compilateur) est systématiquement envoyé dans un header HTTP dédié lors de toute requête RPC (qui est encore une fois une requête faite via XMLHttpRequest). En son absence ou cas de valeur inattendue, la servlet lance une <em>SecurityException</em> ; le traitement s&#8217;arrête là. Ce simple ajout du header complique la tâche au potentiel attaquant. En effet, l&#8217;attaque CSRF par requête POST passe par la soumission d&#8217;un formulaire, le XMLHttpRequest cross-domain est interdit. Or l&#8217;ajout d&#8217;un header HTTP n&#8217;est pas possible dans un formulaire HTML.</p>
<p>Cependant, comme nous l&#8217;avons vu lors de l&#8217;élimination du referer dans notre stratégie de sécurisation, des configurations permettront cet ajout. Il ne suffit donc pas pour une protection exhaustive.</p>
<p>Depuis sa version 2.3, le framework propose un mécanisme plus complet. C’est un hash MD5 de l’identifiant de session qui est envoyé avec les requêtes RPC, sa présence est automatiquement contrôlée par le service GWT. L&#8217;interface d&#8217;un service protégé et son implémentation hériteront respectivement d&#8217;une interface et d&#8217;une classe spécifique. Enfin, une servlet sera dédiée à la récupération du jeton. La mise en place exacte d&#8217;un service RPC jouissant de ce mécanisme passe par les opérations suivantes :</p>
<h5>Définition de l&#8217;interface du service</h5>
<pre class="brush:java">// à noter que les développeurs GWT ont préféré l'appellation XSRF - plus rare - à CSRF
public interface SecuredService extends XsrfProtectedService {
	void doSomethingReallyImportant();
}</pre>
<h5>Implémentation du service</h5>
<pre class="brush:java">public class SecuredServiceImpl extends XsrfProtectedServiceServlet implements SecuredService{

    @Override
    public void doSomethingReallyImportant() {
        yeahNowWeAreReallyGonnaDoIt();
    }

    // [...]

}</pre>
<h5>Déclaration de la servlet délivrant le jeton (token)</h5>
<p>Dans le web.xml :</p>
<pre class="brush:xml">&lt;context-param&gt;
	&lt;param-name&gt;gwt.xsrf.session_cookie_name&lt;/param-name&gt;
	&lt;param-value&gt;JSESSIONID&lt;/param-value&gt;
&lt;/context-param&gt;&lt;servlet&gt;
	&lt;servlet-name&gt;XsrfTokenServiceServlet&lt;/servlet-name&gt;
	&lt;servlet-class&gt;com.google.gwt.user.server.rpc.XsrfTokenServiceServlet&lt;/servlet-class&gt;
&lt;/servlet&gt;
&lt;servlet-mapping&gt;
	&lt;servlet-name&gt;XsrfTokenServiceServlet&lt;/servlet-name&gt;
	&lt;url-pattern&gt;/xsrfTokenService&lt;/url-pattern&gt;
&lt;/servlet-mapping&gt;</pre>
<h5>Définition du nom du cookie à utiliser</h5>
<p>Le nom du cookie à utiliser est aussi déclaré dans le web.xml. Au besoin il serait possible de créer un cookie dédié à cela, indépendamment de la session.</p>
<pre class="brush:xml">&lt;context-param&gt;
	&lt;param-name&gt;gwt.xsrf.session_cookie_name&lt;/param-name&gt;
	&lt;param-value&gt;session-id&lt;/param-value&gt;
&lt;/context-param&gt;</pre>
<h5>Utilisation du service sécurisé</h5>
<p>L&#8217;utilisation du mécanisme se fait en deux phases dans le code GWT. Il faut d&#8217;abord récupérer et stocker quelque part le jeton.</p>
<pre class="brush:java">private XsrfToken xsrfToken;

public void fetchXsrfToken() {
	XsrfTokenServiceAsync xsrfTokenService = GWT.create(XsrfTokenService.class);
		// ces interfaces sont fournies par le SDK avec la servlet

	((ServiceDefTarget) xsrfTokenService).setServiceEntryPoint("xsrfTokenService"); // défini
	xsrfTokenService.getNewXsrfToken(new AsyncCallback() {
		public void onSuccess(XsrfToken result) {
			xsrfToken = result;
		}

		public void onFailure(Throwable caught) {
			// une RpcTokenException peut notamment être levée si le cookie
			// est inexistant ou vide

			// [...]
		}
	});
}</pre>
<p>Il doit ensuite être injecté aux instances de services d&#8217;appel asynchrone.</p>
<pre class="brush:java">SecuredServiceAsync securedService = GWT.create(SecuredService.class);
((HasRpcToken) securedService).setRpcToken(xsrfToken);
securedService.doSomethingReallyImportant(new AsyncCallback() {
	@Override
	public void onFailure(Throwable caught) {
		// [...]
	}

	@Override
	public void onSuccess(Void result) {
		// [...]
	}
});</pre>
<p>Tous les détails sont documentés dans la Javadoc de la servlet XsrfTokenServiceServlet.</p>
<h4>L’utiliser, ou pas ?</h4>
<p>Cette même Javadoc commence par l&#8217;avertissement suivant :</p>
<blockquote><p><em>EXPERIMENTAL and subject to change. Do not use this in production code</em></p></blockquote>
<p>Il est fort probable que les développeurs de GWT souhaitent l’intégrer de façon plus transparente, plus élégante et plus propre au framework. On pourrait entre autres générer le hash MD5 du cookie côté GWT.</p>
<p>Que faire en attendant ? Notre préconisation est de préférer l’utilisation de ces classes « expérimentales » si vous souhaitez vous défendre contre ce type d&#8217;attaque. Une implémentation de votre cru fera le job, mais vous n&#8217;y gagnerez rien. Si une version future de GWT propose une solution mieux intégrée, nul doute que le refactoring sera mineur&#8230;</p>
<p>Si jamais, pour une raison ou une autre (je pense notamment au refactoring d&#8217;une application existante), la récupération asynchrone du jeton vous pose problème, l&#8217;objet <a title="Javadoc Dictionary" href="http://google-web-toolkit.googlecode.com/svn/javadoc/latest/com/google/gwt/i18n/client/Dictionary.html" target="_blank">Dictionary</a> permet de récupérer une variable définie dans la page HTML hôte de l&#8217;application GWT. Il suffit alors de délivrer cette page via une servlet (ou autre si vous avez déjà&#8230;) et d&#8217;y injecter le jeton.</p>
<h3>RequestBuilder et RequestFactory</h3>
<p>Un petit avantage des applications Ajax pour lutter contre les CSRF est, encore une fois, que l&#8217;objet XMLHttpRequest permet la manipulation des headers HTTP. Utiliser le header pour y glisser un champ dédié à notre jeton sera plus pratique qu’une variable dans le corps de la requête – qui restera dédié à la donnée.</p>
<p>RequestBuilder est le pendant de XMLHttpRequest du monde JavaScript, c&#8217;est la classe qui permet de faire des requête GET ou POST &laquo;&nbsp;à la main&nbsp;&raquo;. Par rapport au XMLHttpRequest initial, RequestBuilder n&#8217;est qu&#8217;une façade qui reprend une syntaxe plus proche de ce que l&#8217;on trouvera dans le monde Java, mais uniquement côté client. De ce fait, elle permet l&#8217;utilisation de GWT avec des stacks autres que Java côté serveur.</p>
<p>RequestFactory est l&#8217;API proposée avec la version 2.1 de GWT en alternative à RPC. Son principal atout aujourd&#8217;hui : elle manipule des DTO outillés, de telle façon qu&#8217;une opération save(myDto) ne fera transiter dans la requête HTTP que les champs effectivement modifiés de l&#8217;objet.</p>
<p>Contrairement à RPC le framework ne gère seul le jeton ni pour RequestBuilder ni pour RequestFactory. L&#8217;opération préconisée sera d&#8217;utiliser un champ de header pour RequestBuilder, afin de ne pas polluer le corps de la requête. Dans le cas de RequestFactory, la séparation headers/corps de requête est en fait moins substantielle, du fait de la forme déjà spécifique du corps de requête. L&#8217;exemple donné passe cependant par un header.</p>
<p>Notre préconisation sera d&#8217;utiliser au maximum l&#8217;outillage existant pour RPC, il tient la route et cela semble une bonne stratégie en cas de positionnement futur du framework pour la sécurisation des RequestBuilder et RequestFactory (bien sûr, si vous utilisez RequestBuilder avec autre chose que Java côté serveur, cette remarque n&#8217;est pas à prendre en compte).</p>
<h4>Pour RequestBuilder</h4>
<h5>Côté client</h5>
<p>Comme en RPC, il conviendra tout d&#8217;abord de récupérer le token (pour cela, voir le code fourni pour le mécanisme RPC), puis d&#8217;injecter le header :</p>
<pre class="brush:java">RequestBuilder requestBuilder = new RequestBuilder(RequestBuilder.POST, "");
requestBuilder.setHeader("X-XSRF-Cookie", xsrfToken.getToken());
requestBuilder.sendRequest(null, new RequestCallback() {
	@Override
	public void onResponseReceived(Request request, Response response) {
		// [...]
	}

	@Override
	public void onError(Request request, Throwable exception) {
		// [...]
	}
});</pre>
<p>Dans le cas d&#8217;un serveur non-Java, deux solutions : générer le MD5 en utilisant un script JS trouvé sur le net (les principaux frameworks n&#8217;en proposent pas, mais voir par exemple <a title="MD5 en JavaScript" href="http://actuel.fr.selfhtml.org/articles/javascript/md5/index.htm" target="_blank">ici</a>), ou procéder au hashage côté serveur et le redescendre côté client (comme avec RPC, en asynchrone ou via l&#8217;objet <a title="Javadoc Dictionary" href="http://google-web-toolkit.googlecode.com/svn/javadoc/latest/com/google/gwt/i18n/client/Dictionary.html" target="_blank">Dictionary</a> et la page HTML hôte).</p>
<h5>Côté serveur</h5>
<p>Voici un exemple avec une simple servlet Java. La validation est grandement reprise du code utilisé pour RPC, et exploite les même classes utilitaires fournies par GWT :</p>
<pre class="brush:java">public class SecuredServlet extends HttpServlet {

	@Override
	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		validateXsrfToken(request);
		super.service(request, response);
	}

	protected void validateXsrfToken(HttpServletRequest request) throws RpcTokenException {
		// RpcTokenException est propre à GWT

		String xsrfToken = request.getHeader("XSRF-Token");
			// le header que nous avons injecté
		if (xsrfToken == null) {
			throw new RpcTokenException("XSRF token missing");
		}

		Cookie sessionCookie = Util.getCookie(request, "session-id", false);
			// com.google.gwt.user.server.Util est une classe utilitaire interne GWT
		if (sessionCookie == null || sessionCookie.getValue() == null || sessionCookie.getValue().length() == 0) {
			throw new RpcTokenException("Session cookie is missing or empty! " + "Unable to verify XSRF cookie");
		}
		String expectedToken = Utility.toHexString(Utility.getMd5Digest(sessionCookie.getValue().getBytes()));
			// de com.google.gwt.util.tools.Utility ...

		if (!expectedToken.equals(xsrfToken)) {
			throw new RpcTokenException("Invalid XSRF token");
		}
	}

	// [...]

}</pre>
<h4>Pour RequestFactory</h4>
<h5>Côté client</h5>
<p>Etendre DefaultRequestTransport pour injecter le header :</p>
<pre class="brush:java">public class SecuredRequestTransport extends DefaultRequestTransport {

	protected XsrfToken xsrfToken;

	public SecuredRequestTransport(XsrfToken xsrfToken) {
		this.xsrfToken = xsrfToken;
	}

	@Override
	protected void configureRequestBuilder(RequestBuilder builder) {
		super.configureRequestBuilder(builder);
		builder.setHeader("XSRF-Token", xsrfToken.getToken());
	}
}</pre>
<p>A noter qu&#8217;on aurait pu aussi enrichir le corps de requête, comme dit plus haut.</p>
<p>Utiliser ensuite une instance de notre SecuredRequestTransport au lieu de DefaultRequestTransport avec nos RequestFactory :</p>
<pre class="brush:java">EventBus eventBus = new SimpleEventBus();
SecuredRequestTransport securedRequestTransport = new SecuredRequestTransport(xsrfToken);
MyRequestFactory myRequestFactory = GWT.create(MyRequestFactory.class);
myRequestFactory.initialize(eventBus, securedRequestTransport);</pre>
<h5>Côté serveur</h5>
<p>Côté serveur, il sera nécessaire de créer une classe héritant de RequestFactoryServlet. Le code est strictement le même que l&#8217;exemple donné pour RequestBuilder, le validateXsrfToken() peut être appelé dans un <em>doPost()</em> enrichi (au lieu de <em>service()</em>).</p>
<pre class="brush:java">public class SecuredRequestFactoryServlet extends RequestFactoryServlet {

	@Override
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		validateXsrfToken(request);
		super.doPost(request, response);
	}

	// ce code est strictement le même que pour la SecuredServlet plus haut
	protected void validateXsrfToken(HttpServletRequest request) throws RpcTokenException {
		// RpcTokenException est propre à GWT

		String xsrfToken = request.getHeader("XSRF-Token");
			// le header que nous avons injecté
		if (xsrfToken == null) {
			throw new RpcTokenException("XSRF token missing");
		}

		Cookie sessionCookie = Util.getCookie(request, "session-id", false);
			// com.google.gwt.user.server.Util est une classe utilitaire interne GWT
		if (sessionCookie == null || sessionCookie.getValue() == null || sessionCookie.getValue().length() == 0) {
			throw new RpcTokenException("Session cookie is missing or empty! " + "Unable to verify XSRF cookie");
		}
		String expectedToken = Utility.toHexString(Utility.getMd5Digest(sessionCookie.getValue().getBytes()));
			// de com.google.gwt.util.tools.Utility ...

		if (!expectedToken.equals(xsrfToken)) {
			throw new RpcTokenException("Invalid XSRF token");
		}
	}

	// [...]

}</pre>
<p>Dans le web.xml, déclarer cette servlet au lieu de RequestFactoryServlet.</p>
<h3>Conclusion</h3>
<p>Les CSRF rentrent dans la catégorie des failles qui doivent être connues du développeur qui manipule un framework de présentation quel qu&#8217;il soit. Étonnamment, nombre de frameworks font preuve de peu de maturité dans l&#8217;intégration de solutions pour s&#8217;en prémunir.</p>
<p>GWT permet de mettre en place des solutions relativement facile à maintenir et à surveiller. Les failles sont peut-être plus complexes à appréhender, mais sont aussi plus faciles à isoler avec une application riche qu&#8217;avec une application web standard. De même, une application GWT existante à sécuriser devrait aisément se refactorer.</p>
<p>Certains frameworks, notamment Rails, résilient la session en cas de jeton attendu non détecté, ce qui peut constituer une sécurité supplémentaire. La RpcTokenException de GWT pourrait par ailleurs nous permettre de prévenir l&#8217;utilisateur d&#8217;une probable tentative d&#8217;attaque, via une alerte JavaScript <a title="GWT Window.alert()" href="http://google-web-toolkit.googlecode.com/svn/javadoc/latest/com/google/gwt/user/client/Window.html#alert%28java.lang.String%29" target="_blank">Window.alert()</a>, afin de sortir d&#8217;une éventuelle frame cachée.</p>
<p>En cas de besoin, dans une démarche de qualité, on pourra chercher à l&#8217;aide d&#8217;un outil comme Sonar des traces de non respects de la marche à suivre. Par exemple en vérifiant que nos interfaces de service RPC héritent de XsrfProtectedService et non plus de RemoteService. Ou encore en créant une classe SecuredRequestBuilder dont le constructeur exige le jeton, et vérifier que la RequestBuilder standard n&#8217;est plus utilisée.</p>
<p>Un prochain article abordera les failles XSS, les solutions proposées par le framework pour s&#8217;en prémunir, et traitera rapidement des autres points top 10 OWASP dans le contexte d&#8217;une application GWT.</p>

 <img src="http://blog.octo.com/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=27763" width="1" height="1" style="display: none;" /><p>Suggestion d'articles :</p><ol>
<li><a href='http://blog.octo.com/initiation-a-la-securite-des-web-services/' rel='bookmark' title='Initiation à la sécurité des Web Services'>Initiation à la sécurité des Web Services</a></li>
<li><a href='http://blog.octo.com/securite-des-services-web-1ere-partie/' rel='bookmark' title='Sécurité des services web – 1ère partie'>Sécurité des services web – 1ère partie</a></li>
<li><a href='http://blog.octo.com/html5-offline-et-securite/' rel='bookmark' title='HTML5, offline et sécurité'>HTML5, offline et sécurité</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://blog.octo.com/gwt-et-securite-se-premunir-des-csrf/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Les grandes tendances de Devoxx 2011</title>
		<link>http://blog.octo.com/les-grandes-tendances-de-devoxx-2011/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=les-grandes-tendances-de-devoxx-2011</link>
		<comments>http://blog.octo.com/les-grandes-tendances-de-devoxx-2011/#comments</comments>
		<pubDate>Sat, 03 Dec 2011 12:25:36 +0000</pubDate>
		<dc:creator>Michel Domenjoud</dc:creator>
				<category><![CDATA[Actualité]]></category>
		<category><![CDATA[Architecture et technologies]]></category>
		<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://blog.octo.com/?p=28166</guid>
		<description><![CDATA[La plus grand conférence de la communauté Java avec JavaOne a eu lieu à Anvers en Belgique au mois de Novembre. Cette année, les thèmes principaux de Devoxx étaient (sans ordre particulier): Le futur de Java Les langages alternatifs sur la JVM HTML5 JavaFX Android Un peu de Cloud, de NoSQL et d&#8217;architecture haute performance [...]
Suggestion d'articles :<ol>
<li><a href='http://blog.octo.com/paris-web-2010-les-grandes-tendances/' rel='bookmark' title='Paris Web 2010: les grandes tendances'>Paris Web 2010: les grandes tendances</a></li>
<li><a href='http://blog.octo.com/one-day-devoxx/' rel='bookmark' title='One day @ Devoxx'>One day @ Devoxx</a></li>
<li><a href='http://blog.octo.com/last-day-devoxx/' rel='bookmark' title='Last day @Devoxx'>Last day @Devoxx</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[
<div class="topsy_widget_data topsy_theme_blue" style="float: right;margin-left: 0.75em; background: url(data:,%7B%20%22url%22%3A%20%22http%253A%252F%252Fblog.octo.com%252Fles-grandes-tendances-de-devoxx-2011%252F%22%2C%20%22style%22%3A%20%22small%22%2C%20%22title%22%3A%20%22Les%20grandes%20tendances%20de%20Devoxx%202011%22%20%7D);"></div>
<p><img class="aligncenter" title="Devoxx 2011" src="http://www.sogeti.be/Global/header%20images/Special%20format/DevoxxTransparent.png" alt="" width="945" height="354" /></p>
<p>La plus grand conférence de la communauté Java avec JavaOne a eu lieu à Anvers en Belgique au mois de Novembre. Cette année, les thèmes principaux de Devoxx étaient (sans ordre particulier):</p>
<ul>
<li>Le futur de Java</li>
<li>Les langages alternatifs sur la JVM</li>
<li>HTML5</li>
<li>JavaFX</li>
<li>Android</li>
<li>Un peu de Cloud, de NoSQL et d&#8217;architecture haute performance</li>
</ul>
<p>Nous avons aussi eu droit à une grande annonce pour une nouvelle conférence qui démarre en 2012 : <a title="Devoxx France" href="http://www.devoxx.com/display/FR12/Accueil">Devoxx France</a>!</p>
<p>Bien sûr, OCTO était sur place. Dans cet article, nous ne couvrirons pas toute la conférence en détail, de nombreux blogs l&#8217;ont déjà très bien fait. Nous allons néanmoins vous résumer les grandes tendances de cette édition et vous donner nos impressions à froid.</p>
<p>La suite de cet article en anglais, international oblige! <a title="Devoxx 2011, the main trends" href="http://blog.octo.com/en/devoxx-2011-the-main-trends/">Lire la suite&#8230;</a></p>

 <img src="http://blog.octo.com/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=28166" width="1" height="1" style="display: none;" /><p>Suggestion d'articles :</p><ol>
<li><a href='http://blog.octo.com/paris-web-2010-les-grandes-tendances/' rel='bookmark' title='Paris Web 2010: les grandes tendances'>Paris Web 2010: les grandes tendances</a></li>
<li><a href='http://blog.octo.com/one-day-devoxx/' rel='bookmark' title='One day @ Devoxx'>One day @ Devoxx</a></li>
<li><a href='http://blog.octo.com/last-day-devoxx/' rel='bookmark' title='Last day @Devoxx'>Last day @Devoxx</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://blog.octo.com/les-grandes-tendances-de-devoxx-2011/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Utilisation avancée de CXF : les intercepteurs</title>
		<link>http://blog.octo.com/utilisation-avancee-de-cxf-les-intercepteurs/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=utilisation-avancee-de-cxf-les-intercepteurs</link>
		<comments>http://blog.octo.com/utilisation-avancee-de-cxf-les-intercepteurs/#comments</comments>
		<pubDate>Fri, 02 Dec 2011 08:19:18 +0000</pubDate>
		<dc:creator>Mikael Robert</dc:creator>
				<category><![CDATA[Architecture et technologies]]></category>
		<category><![CDATA[CXF]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Java EE]]></category>
		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://blog.octo.com/?p=28130</guid>
		<description><![CDATA[Le framework CXF est aujourd&#8217;hui probablement le meilleur framework pour implémenter des web services selon la spécification JAX-WS en Java. Ayant réalisé un projet d&#8217;envergure autour de CXF, cet article n&#8217;a pas pour but d&#8217;être une initiation à ce framework car les tutoriaux de base de la documentation sont très bien faits ( http://cxf.apache.org/docs/index.html). Nous [...]]]></description>
			<content:encoded><![CDATA[
<div class="topsy_widget_data topsy_theme_blue" style="float: right;margin-left: 0.75em; background: url(data:,%7B%20%22url%22%3A%20%22http%253A%252F%252Fblog.octo.com%252Futilisation-avancee-de-cxf-les-intercepteurs%252F%22%2C%20%22shorturl%22%3A%20%22http%3A%2F%2Fbit.ly%2FutfbMk%22%2C%20%22style%22%3A%20%22small%22%2C%20%22title%22%3A%20%22Utilisation%20avanc%C3%A9e%20de%20CXF%20%3A%20les%20intercepteurs%22%20%7D);"></div>
<p>Le framework <strong>CXF</strong> est aujourd&#8217;hui probablement le meilleur framework pour implémenter des web services selon la spécification <strong>JAX-WS</strong> en Java. Ayant réalisé un projet d&#8217;envergure autour de CXF, cet article n&#8217;a pas pour but d&#8217;être une initiation à ce framework car les tutoriaux de base de la documentation sont très bien faits (<a href=" http://cxf.apache.org/docs/index.html" target="_blank"> http://cxf.apache.org/docs/index.html</a>). Nous allons plutôt, dans une série d&#8217;articles, tenter de vous présenter quelques <strong>&laquo;&nbsp;tips avancés&nbsp;&raquo;</strong> sur CXF.</p>
<p>Une grande qualité de CXF est d&#8217;être un framework très modulaire de par sa conception autour d&#8217;un bus et d&#8217;une chaîne <strong>d&#8217;intercepteurs</strong>.</p>
<p>Lorsqu&#8217;on met en place un ensemble de WebServices, on peut être amené à effectuer un traitement commun à tous ces web services. Par exemple, rattraper les exceptions et maîtriser la <em>soap:foault</em> qui sera renvoyée au client. Ce type de traitement peut être réalisé de diverses façons, mais une bonne pratique est d&#8217;utiliser des <strong>intercepteurs</strong>.</p>
<p>La  <a title="http://cxf.apache.org/docs/interceptors.html" href="http://cxf.apache.org/docs/interceptors.html">documentation officielle</a>  explique très bien les bases de la mise en place d&#8217;intercepteurs.<br />
CXF découpe en phases le cycle de vie d&#8217;un message depuis son arrivée en passant par son traitement jusqu&#8217;à la réponse à celui-ci. C&#8217;est sur ces phases que l&#8217;on &laquo;&nbsp;branche&nbsp;&raquo; les intercepteurs afin qu&#8217;ils puissent traiter un message en fonction de son étape de cycle de vie.<br />
On peut aussi spécifier explicitement que l&#8217;on branche un intercepteur avant ou après un autre intercepteur sur la même phase.</p>
<p><span id="more-28130"></span></p>
<p>Le schéma ci-dessous donne un exemple d&#8217;architecture projet simplifié pour CXF avec une étape de sécurité, une étape de logging, une étape de validation des données et une étape de traitement des erreurs &#8211; cliquer pour zoommer :</p>
<p><a href="http://blog.octo.com/wp-content/uploads/2011/11/cxf-archi.png"><img class="alignnone size-medium wp-image-28133" title="cxf-archi" src="http://blog.octo.com/wp-content/uploads/2011/11/cxf-archi-300x133.png" alt="" width="300" height="133" /></a></p>
<p>Nous allons maintenant vous présenter deux intercepteurs en exemple.<br />
L&#8217;ensemble du code présenté ci dessous est disponible sur <a title="https://github.com/mikrob/cxf-poc" href="https://github.com/mikrob/cxf-poc" target="_blank">github</a> dans un projet maven. Ce code a été testé et déployé sous <em>JBoss AS 7</em>.</p>
<h2>Mise en place d&#8217;un WebService simple</h2>
<p>Pour nos exemples, nous avons besoin d&#8217;un <em>WebService</em> à appeler.</p>
<p>Celui-ci aura deux WebMethod :</p>
<ul>
<li>une simple qui répond &laquo;&nbsp;hello&nbsp;&raquo;</li>
<li>une autre générant des exceptions, pour illustrer l&#8217;interception de celles-ci.</li>
</ul>
<p><strong> Le code de notre WebService d&#8217;exemple : </strong></p>

<div class="wp_codebox"><table><tr id="p2813011"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="code" id="p28130code11"><pre class="java" style="font-family:monospace;">@WebService
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> HelloWorldService <span style="color: #009900;">&#123;</span>
&nbsp;
    @WebMethod
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #003399;">String</span> sayHello<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #0000ff;">&quot;Hello world&quot;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    @WebMethod
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> makeBusinessException<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">throws</span> BusinessException <span style="color: #009900;">&#123;</span>
    	<span style="color: #000000; font-weight: bold;">throw</span> <span style="color: #000000; font-weight: bold;">new</span> BusinessException<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>Nous utiliserons dans ce cas la configuration en mode <strong>Spring 3</strong>, par annotation dans le code Java :</p>

<div class="wp_codebox"><table><tr id="p2813012"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
</pre></td><td class="code" id="p28130code12"><pre class="java" style="font-family:monospace;">@Configuration
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> ApplicationConfig <span style="color: #009900;">&#123;</span>
&nbsp;
	@Bean
	<span style="color: #000000; font-weight: bold;">public</span> HelloWorldService helloWorldService<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		<span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000000; font-weight: bold;">new</span> HelloWorldService<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
&nbsp;
	@Bean
	<span style="color: #000000; font-weight: bold;">public</span> XmlInInterceptor xmlInInterceptor<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		<span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000000; font-weight: bold;">new</span> XmlInInterceptor<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
&nbsp;
	@Bean
	<span style="color: #000000; font-weight: bold;">public</span> ExceptionInterceptor exceptionInterceptor<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		<span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000000; font-weight: bold;">new</span> ExceptionInterceptor<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<h2>Récupération du message SOAP avant marshalling</h2>
<p>Pour diverses raisons, il peut être intéressant de récupérer le messages XML (SOAP donc) que les WebServices vont être amenés à recevoir. Le problème est que lorsqu&#8217;on arrive dans la WebMethod d&#8217;un WebService, celui-ci est déjà démarshallé et n&#8217;est plus accessible facilement.<br />
D&#8217;autre part, ce type de traitement uniquement technique n&#8217;a pas à apparaître dans la WebMethod qui ne devrait porter que le code répondant au métier du Web Service. Il faut donc récupérer ce message avant l&#8217;arrivée dans le WebService. Excellent cas d&#8217;usage des intercepteurs.<br />
Cet exemple a été choisi car il ne figure pas dans la documentation. Il a été codé en fouillant le code source de CXF.</p>
<p>A noter qu&#8217;on ne fait que logger le message, cela pourrait être remplacé par la feature de logging de CXF activable dans la configuration Spring :</p>

<div class="wp_codebox"><table><tr id="p2813013"><td class="line_numbers"><pre>1
2
3
4
5
</pre></td><td class="code" id="p28130code13"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;cxf:bus</span> <span style="color: #000000; font-weight: bold;">&gt;</span></span>
	<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;cxf:features<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
		<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;cxf:logging</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
	<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/cxf:features<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/cxf:bus<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></td></tr></table></div>

<p>Néanmoins il peut être utile de logger de façon plus formelle, pour des raisons d&#8217;audit par exemple.</p>
<h3>Interception du message reçu</h3>
<p>Le code suivant est celui de l&#8217;intercepteur qui récupère le XML du message reçu par le WebService.</p>

<div class="wp_codebox"><table><tr id="p2813014"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
</pre></td><td class="code" id="p28130code14"><pre class="java" style="font-family:monospace;">@NoJSR250Annotations
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> XmlInInterceptor <span style="color: #000000; font-weight: bold;">extends</span> AbstractSoapInterceptor <span style="color: #009900;">&#123;</span> 
&nbsp;
	<span style="color: #000000; font-weight: bold;">private</span> Logger logger <span style="color: #339933;">=</span> LoggerFactory.<span style="color: #006633;">getLogger</span><span style="color: #009900;">&#40;</span>XmlInInterceptor.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #000000; font-weight: bold;">public</span> XmlInInterceptor<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		<span style="color: #000000; font-weight: bold;">super</span><span style="color: #009900;">&#40;</span>Phase.<span style="color: #006633;">PRE_PROTOCOL</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		getAfter<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">add</span><span style="color: #009900;">&#40;</span>SAAJInInterceptor.<span style="color: #000000; font-weight: bold;">class</span>.<span style="color: #006633;">getName</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
&nbsp;
	<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> handleMessage<span style="color: #009900;">&#40;</span>SoapMessage msg<span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">throws</span> Fault <span style="color: #009900;">&#123;</span>
		Exchange exchange <span style="color: #339933;">=</span> msg.<span style="color: #006633;">getExchange</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		Endpoint ep <span style="color: #339933;">=</span> exchange.<span style="color: #006633;">get</span><span style="color: #009900;">&#40;</span>Endpoint.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
		ServiceInfo si <span style="color: #339933;">=</span> ep.<span style="color: #006633;">getEndpointInfo</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">getService</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #003399;">String</span> serviceName <span style="color: #339933;">=</span> si.<span style="color: #006633;">getName</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">getLocalPart</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		logger.<span style="color: #006633;">info</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Service name : {}&quot;</span>, serviceName<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
		XMLStreamReader xr <span style="color: #339933;">=</span> msg.<span style="color: #006633;">getContent</span><span style="color: #009900;">&#40;</span>XMLStreamReader.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>xr <span style="color: #339933;">!=</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #666666; font-style: italic;">// If we are not even able to parse the message in the SAAJInInterceptor (CXF internal interceptor) this can be null</span>
			QName name <span style="color: #339933;">=</span> xr.<span style="color: #006633;">getName</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			<span style="color: #003399;">String</span> operationName <span style="color: #339933;">=</span> name.<span style="color: #006633;">getLocalPart</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			logger.<span style="color: #006633;">info</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Operation name : {}&quot;</span>, operationName<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
&nbsp;
		<span style="color: #666666; font-style: italic;">// Set the calling ip</span>
		ServletRequest request <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>ServletRequest<span style="color: #009900;">&#41;</span> msg.<span style="color: #006633;">get</span><span style="color: #009900;">&#40;</span>ServletDestination.<span style="color: #006633;">HTTP_REQUEST</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>request <span style="color: #339933;">!=</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #666666; font-style: italic;">// and if the ServletDestination isn't even processed, the request could be null</span>
			<span style="color: #003399;">String</span> remoteHost <span style="color: #339933;">=</span> request.<span style="color: #006633;">getRemoteHost</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			logger.<span style="color: #006633;">info</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Calling IP : {}&quot;</span>, remoteHost<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
&nbsp;
		<span style="color: #000000; font-weight: bold;">try</span> <span style="color: #009900;">&#123;</span>
			SOAPMessage msgSOAP <span style="color: #339933;">=</span> msg.<span style="color: #006633;">getContent</span><span style="color: #009900;">&#40;</span>SOAPMessage.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			<span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>msgSOAP <span style="color: #339933;">!=</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
				<span style="color: #003399;">ByteArrayOutputStream</span> byteArrayOutputStream <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">ByteArrayOutputStream</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
				msgSOAP.<span style="color: #006633;">writeTo</span><span style="color: #009900;">&#40;</span>byteArrayOutputStream<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
				<span style="color: #003399;">String</span> encoding <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span><span style="color: #009900;">&#41;</span> msg.<span style="color: #006633;">get</span><span style="color: #009900;">&#40;</span>Message.<span style="color: #006633;">ENCODING</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
				<span style="color: #003399;">String</span> xmlRequest <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">String</span><span style="color: #009900;">&#40;</span>byteArrayOutputStream.<span style="color: #006633;">toByteArray</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>, encoding<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
				logger.<span style="color: #006633;">info</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Xml Request was : {}&quot;</span>, xmlRequest<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			<span style="color: #009900;">&#125;</span>
		<span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">catch</span> <span style="color: #009900;">&#40;</span><span style="color: #003399;">IOException</span> e<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
			<span style="color: #666666; font-style: italic;">// process io exception</span>
		<span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">catch</span> <span style="color: #009900;">&#40;</span>SOAPException e<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
			<span style="color: #666666; font-style: italic;">// process soap exception</span>
		<span style="color: #009900;">&#125;</span>
&nbsp;
	<span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>Cet intercepteur est donc branché en Phase <em>Pre-Protocol</em>. Cela nous permet de récupérer le XML avant qu&#8217;il ne soit unmarshallé par les intercepteurs JAXB de CXF.</p>
<p>Comme vous pouvez le voir, on extrait d&#8217;autres informations utiles du SoapMessages, tel que le nom du service appelée, l&#8217;opération appelée et l&#8217;hôte appelant. Ce code est un peu opaque. De façon générale, la programmation d’intercepteur est mal documentée. Le conseil que l’on pourrait donner est de s’inspirer d’un intercepteur similaire et déjà existant. Il faut fouiller car il y en a beaucoup… eux aussi non documenté.</p>
<p>Dans le cas présent, le fonctionnement est le suivant. Un SoapMessage CXF est une grosse HashMap contenant toute sorte de choses. Il faut donc faire un getContent vers d’un SOAPMessage version java pour récupérer l’objet en question. Ensuite, on l’extrait via un ByteArrayOutputStream que l’on insère dans une String en prenant bien soin d’utiliser l’encoding du message.</p>
<p>L’annotation @NoJSR250Annotations est utilisée pour indiquer à CXF que cette classe ne contient pas d’annotation provenant de la JSR 250 et qu’il n’est donc pas nécessaire d’en charger. Cela accélère le démarrage de l’application.</p>
<h3>Interception de la réponse émise</h3>
<p>Voici maintenant l&#8217;intercepteur utilisé en sortie qui récupère dans ce cas le XML émis par CXF pour répondre à l&#8217;appel de WebService.<br />
Celui-ci est branché en phase <em>PRE_STREAM</em>, juste avant l&#8217;envoi du message au client donc.</p>

<div class="wp_codebox"><table><tr id="p2813015"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
</pre></td><td class="code" id="p28130code15"><pre class="java" style="font-family:monospace;">@NoJSR250Annotations
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> XmlOutInterceptor <span style="color: #000000; font-weight: bold;">extends</span> AbstractSoapInterceptor <span style="color: #009900;">&#123;</span>
&nbsp;
	<span style="color: #000000; font-weight: bold;">private</span> Logger logger <span style="color: #339933;">=</span> LoggerFactory.<span style="color: #006633;">getLogger</span><span style="color: #009900;">&#40;</span>XmlOutInterceptor.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #000000; font-weight: bold;">public</span> XmlOutInterceptor<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		<span style="color: #000000; font-weight: bold;">super</span><span style="color: #009900;">&#40;</span>Phase.<span style="color: #006633;">PRE_STREAM</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
&nbsp;
	<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> handleMessage<span style="color: #009900;">&#40;</span>SoapMessage message<span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">throws</span> Fault <span style="color: #009900;">&#123;</span>
&nbsp;
		<span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">OutputStream</span> os <span style="color: #339933;">=</span> message.<span style="color: #006633;">getContent</span><span style="color: #009900;">&#40;</span><span style="color: #003399;">OutputStream</span>.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>os <span style="color: #339933;">==</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
			<span style="color: #000000; font-weight: bold;">return</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
		<span style="color: #000000; font-weight: bold;">final</span> CacheAndWriteOutputStream newOut <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> CacheAndWriteOutputStream<span style="color: #009900;">&#40;</span>os<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		message.<span style="color: #006633;">setContent</span><span style="color: #009900;">&#40;</span><span style="color: #003399;">OutputStream</span>.<span style="color: #000000; font-weight: bold;">class</span>, newOut<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
		newOut.<span style="color: #006633;">registerCallback</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> LoggingCallback<span style="color: #009900;">&#40;</span>message, os<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
&nbsp;
	<span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">class</span> LoggingCallback <span style="color: #000000; font-weight: bold;">implements</span> CachedOutputStreamCallback <span style="color: #009900;">&#123;</span>
&nbsp;
		<span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">final</span> Message message<span style="color: #339933;">;</span>
		<span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">OutputStream</span> origStream<span style="color: #339933;">;</span>
&nbsp;
		<span style="color: #000000; font-weight: bold;">public</span> LoggingCallback<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">final</span> Message msg, <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">OutputStream</span> os<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
			<span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">message</span> <span style="color: #339933;">=</span> msg<span style="color: #339933;">;</span>
			<span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">origStream</span> <span style="color: #339933;">=</span> os<span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
&nbsp;
		<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> onFlush<span style="color: #009900;">&#40;</span>CachedOutputStream cos<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
&nbsp;
		<span style="color: #009900;">&#125;</span>
&nbsp;
		<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> onClose<span style="color: #009900;">&#40;</span>CachedOutputStream cos<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
			<span style="color: #003399;">String</span> encoding <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span><span style="color: #009900;">&#41;</span> message.<span style="color: #006633;">get</span><span style="color: #009900;">&#40;</span>Message.<span style="color: #006633;">ENCODING</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			<span style="color: #003399;">String</span> ct <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span><span style="color: #009900;">&#41;</span> message.<span style="color: #006633;">get</span><span style="color: #009900;">&#40;</span>Message.<span style="color: #006633;">CONTENT_TYPE</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			StringBuilder builder <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> StringBuilder<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			<span style="color: #000000; font-weight: bold;">try</span> <span style="color: #009900;">&#123;</span>
				writePayload<span style="color: #009900;">&#40;</span>builder, cos, encoding, ct<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			<span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">catch</span> <span style="color: #009900;">&#40;</span><span style="color: #003399;">IOException</span> ex<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
				<span style="color: #000000; font-weight: bold;">throw</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">RuntimeException</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Cannot generate audit log for soap response&quot;</span>, ex<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			<span style="color: #009900;">&#125;</span>
&nbsp;
			<span style="color: #003399;">String</span> msg <span style="color: #339933;">=</span> builder.<span style="color: #006633;">toString</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			logger.<span style="color: #006633;">info</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;OUT MESSAGE {}&quot;</span>, msg<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			message.<span style="color: #006633;">setContent</span><span style="color: #009900;">&#40;</span><span style="color: #003399;">OutputStream</span>.<span style="color: #000000; font-weight: bold;">class</span>, origStream<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
		<span style="color: #009900;">&#125;</span>
&nbsp;
		<span style="color: #000000; font-weight: bold;">protected</span> <span style="color: #000066; font-weight: bold;">void</span> writePayload<span style="color: #009900;">&#40;</span>StringBuilder builder, CachedOutputStream cos, <span style="color: #003399;">String</span> encoding, <span style="color: #003399;">String</span> contentType<span style="color: #009900;">&#41;</span>
				<span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">IOException</span> <span style="color: #009900;">&#123;</span>
			<span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>StringUtils.<span style="color: #006633;">isEmpty</span><span style="color: #009900;">&#40;</span>encoding<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
				cos.<span style="color: #006633;">writeCacheTo</span><span style="color: #009900;">&#40;</span>builder<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			<span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">else</span> <span style="color: #009900;">&#123;</span>
				cos.<span style="color: #006633;">writeCacheTo</span><span style="color: #009900;">&#40;</span>builder, encoding<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			<span style="color: #009900;">&#125;</span>
		<span style="color: #009900;">&#125;</span>
	<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>Ce code semble encore plus complexe que le précédent pour simplement aller chercher un fragment de XML dans le framework.<br />
En fait nous l&#8217;avons en partie repris de la LoggingFeature de CXF ainsi que de quelques astuces glanées dans le code du framework.<br />
L&#8217;idée globale est d&#8217;intercepter le stream de sortie à l&#8217;aide d&#8217;un callback (LoggingCallback). Le callback en question récupère l&#8217;encoding du flux, lis le flux, le transforme en chaine de caractères, puis le replace dans le flux afin que la réponse soit tout de même émise au client&#8230; c&#8217;est mieux.</p>
<h3>Configuration Spring</h3>
<p>Et pour finir voici la configuration Spring de notre WebService et de ses intercepteurs :</p>
<p><strong> Configuration Spring :</strong></p>

<div class="wp_codebox"><table><tr id="p2813016"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
</pre></td><td class="code" id="p28130code16"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;import</span> <span style="color: #000066;">resource</span>=<span style="color: #ff0000;">&quot;classpath:META-INF/cxf/cxf.xml&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;context:annotation-config</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
&nbsp;
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;bean</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;com.octo.cxf.config.ApplicationConfig&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
&nbsp;
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;bean</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;saajInInterceptor&quot;</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;org.apache.cxf.binding.soap.saaj.SAAJInInterceptor&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
&nbsp;
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;cxf:bus</span> <span style="color: #000000; font-weight: bold;">&gt;</span></span>
	<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;cxf:features<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
		<span style="color: #808080; font-style: italic;">&lt;!-- &lt;cxf:logging /&gt; --&gt;</span>
	<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/cxf:features<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
	<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;cxf:inInterceptors<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
		<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;ref</span> <span style="color: #000066;">bean</span>=<span style="color: #ff0000;">&quot;saajInInterceptor&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
	<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/cxf:inInterceptors<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/cxf:bus<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
&nbsp;
&nbsp;
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;jaxws:endpoint</span> <span style="color: #000066;">address</span>=<span style="color: #ff0000;">&quot;/helloworld&quot;</span> <span style="color: #000066;">implementor</span>=<span style="color: #ff0000;">&quot;#helloWorldService&quot;</span> <span style="color: #000066;">serviceName</span>=<span style="color: #ff0000;">&quot;helloWorldService&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
	<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;jaxws:inInterceptors<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
		<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;ref</span> <span style="color: #000066;">bean</span>=<span style="color: #ff0000;">&quot;xmlInInterceptor&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
	<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/jaxws:inInterceptors<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
	<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;jaxws:outInterceptors<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
		<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;ref</span> <span style="color: #000066;">bean</span>=<span style="color: #ff0000;">&quot;xmlOutInterceptor&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>		
	<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/jaxws:outInterceptors<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
	<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;jaxws:outFaultInterceptors<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
		<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;ref</span> <span style="color: #000066;">bean</span>=<span style="color: #ff0000;">&quot;exceptionInterceptor&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
	<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/jaxws:outFaultInterceptors<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/jaxws:endpoint<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></td></tr></table></div>

<p>Bien entendu, si on a plusieurs WebServices, il devient tout de suite intéressant de remonter les intercepteurs au niveau du <strong>bus</strong> et non d&#8217;un web service :</p>

<div class="wp_codebox"><table><tr id="p2813017"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
</pre></td><td class="code" id="p28130code17"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;cxf:bus</span> <span style="color: #000000; font-weight: bold;">&gt;</span></span>
		<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;cxf:features<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
			<span style="color: #808080; font-style: italic;">&lt;!-- &lt;cxf:logging /&gt; --&gt;</span>
		<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/cxf:features<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
		<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;cxf:inInterceptors<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
			<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;ref</span> <span style="color: #000066;">bean</span>=<span style="color: #ff0000;">&quot;saajInInterceptor&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
			<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;ref</span> <span style="color: #000066;">bean</span>=<span style="color: #ff0000;">&quot;xmlInInterceptor&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
		<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/cxf:inInterceptors<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
		<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;cxf:outInterceptors<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
			<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;ref</span> <span style="color: #000066;">bean</span>=<span style="color: #ff0000;">&quot;xmlOutInterceptor&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>	
		<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/cxf:outInterceptors<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
		<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;cxf:outFaultInterceptors<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
			<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;ref</span> <span style="color: #000066;">bean</span>=<span style="color: #ff0000;">&quot;exceptionInterceptor&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
		<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/cxf:outFaultInterceptors<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
	<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/cxf:bus<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></td></tr></table></div>

<p>Vous qui êtes perspicaces remarquerez sûrement l’apparition de l’intercepteur SAAJ. C’est celui qui va ajouter le SOAPMessage dans le SoapMessage. Il est donc nécessaire de l’ajouter avant notre intercepteur en entrée. Par défaut, CXF l’exécute en mode lazy au sein d’un autre intercepteur plus loin dans la chaine.</p>
<h2>Interception des exceptions et personnalisation des soap:fault</h2>
<p>Nous allons maintenant voir comment rattraper les erreurs générées par les WebServices et leur code sous jacent pour en faire des <strong>soap:fault</strong> personnalisées.</p>
<p>Le code suivant récupère l&#8217;exception incluse dans le SoapMessage, teste son type et va générer une <strong>soap:fault</strong> en conséquence. Ici, pour simplifier le code, on ne fait qu&#8217;ajouter un code d&#8217;erreur 8 (définit arbitrairement), mais dans une application plus évoluée cela peut être utile d&#8217;y placer ses propres codes d&#8217;erreur.</p>
<p><strong> L&#8217;intercepteur :</strong></p>

<div class="wp_codebox"><table><tr id="p2813018"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
</pre></td><td class="code" id="p28130code18"><pre class="java" style="font-family:monospace;">@NoJSR250Annotations
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> ExceptionInterceptor <span style="color: #000000; font-weight: bold;">extends</span> AbstractSoapInterceptor <span style="color: #009900;">&#123;</span>
&nbsp;
	<span style="color: #000000; font-weight: bold;">public</span> ExceptionInterceptor<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		<span style="color: #000000; font-weight: bold;">super</span><span style="color: #009900;">&#40;</span>Phase.<span style="color: #006633;">PRE_LOGICAL</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
&nbsp;
	<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> handleMessage<span style="color: #009900;">&#40;</span>SoapMessage message<span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">throws</span> Fault <span style="color: #009900;">&#123;</span>
		Fault fault <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>Fault<span style="color: #009900;">&#41;</span> message.<span style="color: #006633;">getContent</span><span style="color: #009900;">&#40;</span><span style="color: #003399;">Exception</span>.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #003399;">Throwable</span> ex <span style="color: #339933;">=</span> fault.<span style="color: #006633;">getCause</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>ex <span style="color: #000000; font-weight: bold;">instanceof</span> BusinessException<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
			BusinessException e <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>BusinessException<span style="color: #009900;">&#41;</span> ex<span style="color: #339933;">;</span>
			generateSoapFault<span style="color: #009900;">&#40;</span>fault, e<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">else</span> <span style="color: #009900;">&#123;</span>
			generateSoapFault<span style="color: #009900;">&#40;</span>fault, <span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
	<span style="color: #009900;">&#125;</span>
&nbsp;
	<span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000066; font-weight: bold;">void</span> generateSoapFault<span style="color: #009900;">&#40;</span>Fault fault, <span style="color: #003399;">Exception</span> e<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
			fault.<span style="color: #006633;">setFaultCode</span><span style="color: #009900;">&#40;</span>createQName<span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">8</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
&nbsp;
	<span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">static</span> QName createQName<span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">int</span> errorCode<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		<span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000000; font-weight: bold;">new</span> QName<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;octo.com&quot;</span>, <span style="color: #003399;">String</span>.<span style="color: #006633;">valueOf</span><span style="color: #009900;">&#40;</span>errorCode<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>Cet intercepteur doit logiquement être branché en sortie, car la soap:fault sera la réponse au message envoyé.</p>
<p><strong>Configuration Spring :</strong></p>

<div class="wp_codebox"><table><tr id="p2813019"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
</pre></td><td class="code" id="p28130code19"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;jaxws:endpoint</span> <span style="color: #000066;">address</span>=<span style="color: #ff0000;">&quot;/helloworld&quot;</span> <span style="color: #000066;">implementor</span>=<span style="color: #ff0000;">&quot;#helloWorldService&quot;</span> <span style="color: #000066;">serviceName</span>=<span style="color: #ff0000;">&quot;helloWorldService&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
	<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;jaxws:inInterceptors<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
		<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;ref</span> <span style="color: #000066;">bean</span>=<span style="color: #ff0000;">&quot;xmlInInterceptor&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
	<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/jaxws:inInterceptors<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
	<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;jaxws:outFaultInterceptors<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
		<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;ref</span> <span style="color: #000066;">bean</span>=<span style="color: #ff0000;">&quot;exceptionInterceptor&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
	<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/jaxws:outFaultInterceptors<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/jaxws:endpoint<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></td></tr></table></div>

<p>Ainsi si on appelle la WebMethod makeBusinessException, on obtient la réponse suivante :</p>

<div class="wp_codebox"><table><tr id="p2813020"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="code" id="p28130code20"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;soap:Envelope</span> <span style="color: #000066;">xmlns:soap</span>=<span style="color: #ff0000;">&quot;http://schemas.xmlsoap.org/soap/envelope/&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
   <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;soap:Body<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;soap:Fault<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
         <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;faultcode</span> <span style="color: #000066;">xmlns:ns1</span>=<span style="color: #ff0000;">&quot;octo.com&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>ns1:8<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/faultcode<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
         <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;faultstring<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Fault occurred while processing.<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/faultstring<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
         <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;detail<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
            <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;ns1:BusinessException</span> <span style="color: #000066;">xmlns:ns1</span>=<span style="color: #ff0000;">&quot;http://services.cxf.octo.com/&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
         <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/detail<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/soap:Fault<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
   <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/soap:Body<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/soap:Envelope<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></td></tr></table></div>

<p>Pour plus de détails je vous invite à vous référer au code sur github : <a title="https://github.com/mikrob/cxf-poc" href="https://github.com/mikrob/cxf-poc" target="_blank">https://github.com/mikrob/cxf-poc</a></p>
<p>J’espère que cette petite immersion dans le monde des intercepteurs CXF vous sera utile. Dans le prochain article, nous verrons des notions de sécurité avancées liées à CXF (nous sortirons un peu du use case authentification avec WS Security déjà souvent présenté).</p>

 <img src="http://blog.octo.com/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=28130" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://blog.octo.com/utilisation-avancee-de-cxf-les-intercepteurs/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>JSR 303 (Bean Validation) : état des lieux</title>
		<link>http://blog.octo.com/jsr-303-bean-validation-etat-des-lieux/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=jsr-303-bean-validation-etat-des-lieux</link>
		<comments>http://blog.octo.com/jsr-303-bean-validation-etat-des-lieux/#comments</comments>
		<pubDate>Wed, 07 Sep 2011 08:30:43 +0000</pubDate>
		<dc:creator>Ahmed Mseddi</dc:creator>
				<category><![CDATA[Architecture et technologies]]></category>
		<category><![CDATA[Apache Bean Validation]]></category>
		<category><![CDATA[Bean Validation]]></category>
		<category><![CDATA[GWT]]></category>
		<category><![CDATA[Hibernate Validator]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[JSR 303]]></category>

		<guid isPermaLink="false">http://blog.octo.com/?p=22103</guid>
		<description><![CDATA[La JSR 303 (Java Specification Request) a été lancée en 2006. Elle a pour objet d&#8217;éviter la duplication de la validation des données dans les diverses couches de l&#8217;application en la localisant dans la définition des Beans Java. Ceci, dans le but de gagner en productivité et d&#8217;éviter les bugs liés à la redondance de la validation. [...]
Suggestion d'articles :<ol>
<li><a href='http://blog.octo.com/tests-unitaires-et-tests-d%e2%80%99interface-sur-iphone-etat-des-lieux/' rel='bookmark' title='Tests unitaires et tests d’interface sur iPhone : État des lieux'>Tests unitaires et tests d’interface sur iPhone : État des lieux</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[
<div class="topsy_widget_data topsy_theme_blue" style="float: right;margin-left: 0.75em; background: url(data:,%7B%20%22url%22%3A%20%22http%253A%252F%252Fblog.octo.com%252Fjsr-303-bean-validation-etat-des-lieux%252F%22%2C%20%22shorturl%22%3A%20%22http%3A%2F%2Fbit.ly%2FowlCq4%22%2C%20%22style%22%3A%20%22small%22%2C%20%22title%22%3A%20%22JSR%20303%20%28Bean%20Validation%29%20%3A%20%C3%A9tat%20des%20lieux%22%20%7D);"></div>
<p>La <a href="http://www.jcp.org/en/jsr/detail?id=303" target="_blank">JSR 303</a> (<em>Java Specification Request</em>) a été lancée en 2006. Elle a pour objet d&#8217;éviter la duplication de la validation des données dans les diverses couches de l&#8217;application en la localisant dans la définition des Beans Java. Ceci, dans le but de gagner en productivité et d&#8217;éviter les bugs liés à la redondance de la validation. 5 ans après son lancement, nous sommes tentés d&#8217;en savoir plus sur le chemin parcouru par cette JSR et surtout de savoir si oui ou non elle a atteint ses objectifs !</p>
<p>Avant toute chose cependant, il est primordial de se poser quelques questions basiques qui nous permettront de comprendre cette JSR. En effet, quels sont les principes de cette JSR ? Quelles sont les différentes implémentations qui en ont été faites ? Sont-elles au même degré de maturité ? Cette JSR s’intègre-t-elle avec les frameworks existants ? Ou se situe-t-elle par rapport aux autres outils de validation ?</p>
<p><span id="more-22103"></span></p>
<h3>La JSR 303 par l&#8217;exemple</h3>
<p>Dans cette partie, après une courte introduction décrivant succinctement la JSR, je présenterai deux exemples : le premier utilise les annotations définies dans la JSR et le deuxième montre comment créer nos propres annotations pour valider une classe Utilisateur. Mais avant toute chose, je vous propose une brève présentation de la JSR.</p>
<h4>Présentation de la JSR</h4>
<p>La JSR 303 définit un modèle de meta-données et une API pour valider les Beans Java. Cette validation s&#8217;effectue en utilisant les annotations mais il est possible d&#8217;utiliser des fichiers XML. Actuellement, cette JSR a passé toutes les étapes (<em>stages</em>) puisqu&#8217;elle en est à la dernière, i.e. celle de <em>Final Release</em> depuis le 16 novembre 2009. Elle était sous la direction d&#8217;<a href="http://emmanuelbernard.com/" target="_blank">Emmanuel Bernard</a>, lead développeur chez JBoss, une division de Red Hat.</p>
<h4>1<sup>er</sup> exemple : utilisation des annotations</h4>
<p>Tout d&#8217;abord voici la classe Utilisateur que je vais utiliser pour illustrer mes exemples :</p>
<pre class="brush:java">public class Utilisateur {

    private String login;
    private String mdp;
    private Date dateDeNaissance;

    //Constructeurs, getters et setters
}</pre>
<p>Pour notre classe Utilisateur, nous avons plusieurs contraintes :</p>
<ul>
<li>Le login ne doit pas être vide</li>
<li>Le mot de passe doit contenir entre 8 et 16 caractères</li>
<li>La date de naissance doit se situer dans le passé</li>
</ul>
<p>Nous allons donc annoter les attributs de notre classe pour prendre en compte ces contraintes :</p>
<pre class="brush:java">public class Utilisateur {

    @NotNull
    private String login;

    @Size(min = 8, max = 16)
    private String mdp;

    @Past
    private Date dateDeNaissance;

    //Constructeurs, getters et setters
}</pre>
<p>Pour illuster cet exemple, on définit une classe Main dans laquelle on instancie un nouvel utilisateur ayant des attributs qui ne respectent pas les contraintes :</p>
<pre class="brush:java">public class Main {

	public static void main(String[] args) throws ParseException {

		Utilisateur user = new Utilisateur();

		long dayInMillis = 24*60*60*1000;

		user.setLogin(null);
		user.setMdp("mdp");
		user.setDateDeNaissance(new Date(System.currentTimeMillis() + dayInMillis ));

		Validator validator = Validation
				.buildDefaultValidatorFactory().getValidator();

		Set&lt;ConstraintViolation&lt;Utilisateur&gt;&gt; violations = validator
				.validate(user);

		System.out.println("Nombre de violations : " + violations.size());

		for (ConstraintViolation
				constraintViolation : violations) {

			System.out.println("Valeur '"+
					constraintViolation.getInvalidValue() +
					"' incorrecte pour '"+
					constraintViolation.getPropertyPath() +
					"' : " +
					constraintViolation.getMessage());
		}
	}
}</pre>
<p>En exécutant le code précédent nous obtenons les sorties suivantes dans la console :</p>
<pre class="brush:text">Nombre de violations : 3
Valeur 'Thu Aug 18 12:13:56 CEST 2011' incorrecte pour 'dateDeNaissance' : doit être dans le passé
Valeur 'mdp' incorrecte pour 'mdp' : la taille doit être entre 8 et 16
Valeur 'null' incorrecte pour 'login' : ne peut pas être nul</pre>
<p>On voit donc qu&#8217;on ne respecte pas les trois contraintes et qu&#8217;on a à chaque fois un message explicatif.</p>
<p>Notons qu&#8217;on aurait tout aussi bien pu définir les contraintes dans un fichier XML <em>constraint-utilisateur.xml</em> :</p>
<pre class="brush:xml"><constraint-mappings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                     xsi:schemaLocation="http://jboss.org/xml/ns/javax/validation/mapping validation-mapping-1.0.xsd"
                     xmlns="http://jboss.org/xml/ns/javax/validation/mapping">
    <default-package>com.octo.jsr303</default-package>
    <bean class="Utilisateur" ignore-annotations="true">
        <field name="login">
            <constraint annotation="javax.validation.constraints.NotNull"/>
        </field>
        <field name="mdp">
            <constraint annotation="javax.validation.constraints.Size">
                <element name="min">8</element>
                <element name="max">16</element>
            </constraint>
        </field>
        <field name="dateDeNaissance">
        	<constraint annotation="javax.validation.constraints.Past"/>
        </field>
    </bean>
</constraint-mappings></pre>
<p>Il aurait ensuite été nécessaire de déclarer ce fichier dans un fichier <em>validation.xml</em> pour qu&#8217;il soit pris en compte. La documentation détaillée de l&#8217;utilisation de la validation XML est disponible <a href="http://docs.jboss.org/hibernate/validator/4.1/reference/en-US/html/validator-xmlconfiguration.html" target="_blank">ici</a>.</p>
<p><span class="Apple-style-span" style="font-weight: bold;">2<sup>ème</sup> exemple : Création d&#8217;une annotation</span></p>
<p>Il est parfois nécessaire de créer ses propres annotations lorsque celles définies par défaut ne répondent pas aux besoins. Imaginons par exemple qu&#8217;on veuille ajouter aux utilisateurs l&#8217;attribut article qui représente un lien vers l&#8217;article favori de l&#8217;utilisateur parmi les articles du blog Octo.</p>
<pre class="brush:java">public class Utilisateur {

	@NotNull
	private String login;

	@Size(min = 8, max = 16)
	private String mdp;

	@Past
	private Date dateDeNaissance;

	@OctoBlog
	private String article;

	// Constructeurs, getters et setters
}</pre>
<p>On commence donc par définir une nouvelle annotation <span style="color: #808080;">@OctoBlog</span> :</p>
<pre class="brush:java">@Constraint(validatedBy = OctoBlogValidator.class)
@Target(value = ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface OctoBlog {

	String message() default "L'article n'appartient pas au blog octo";

	Class&lt;?&gt;[] groups() default {};

	Class&lt;? extends Payload&gt;[] payload() default { };
}</pre>
<p>Pour cette interface il est obligatoire de de redéfinir messages(), groups() et payload. Il est aussi nécessaire de définir l&#8217;annotation <span style="color: #888888;">@Retention</span> au <em><span style="color: #0000ff;">RUNTIME</span></em> pour que la validation s&#8217;effectue. L&#8217;annotation <span style="color: #808080;">@Target</span> sert à dire quel type d&#8217;élément sera validé et <span style="color: #808080;">@Constraint</span> la classe qui validera cet élément.</p>
<p>Ci-dessous la classe de validation :</p>
<pre class="brush:java">public class OctoBlogValidator implements
		ConstraintValidator&lt;OctoBlog, String&gt; {

	@Override
	public void initialize(OctoBlog constraintAnnotation) {

	}

	@Override
	public boolean isValid(String value,
			ConstraintValidatorContext context) {
		return value.startsWith("http://blog.octo.com/");
	}
}</pre>
<p>Pour illustrer ce deuxième exemple, on exécute le main suivant :</p>
<pre class="brush:java">public class Main {

	public static void main(String[] args) throws ParseException {

		Utilisateur user = new Utilisateur();
		Validator validator = Validation
				.buildDefaultValidatorFactory().getValidator();

		user.setLogin("ams");
		user.setMdp("motDePasse");
		user.setDateDeNaissance(new Date(System.currentTimeMillis()));
		user.setArticle("http://www.blog.com/mon-article");

		System.out.println("Première validation : ");
		validateUser(user, validator);

		user.setArticle("http://blog.octo.com/jsr-303-bean-validation-etat-des-lieux");

		System.out.println("Deuxième validation : ");
		validateUser(user, validator);

	}

	private static void validateUser(Utilisateur utilisateur,
			Validator validator) {
		Set&lt;ConstraintViolation&lt;Utilisateur&gt;&gt; violations;
		violations = validator.validate(utilisateur);

		System.out.println("Nombre de violations : " + violations.size());

		for (ConstraintViolation constraintViolation : violations) {

			System.out.println("Valeur '"
					+ constraintViolation.getInvalidValue()
					+ "' incorrecte pour '"
					+ constraintViolation.getPropertyPath() + "' : "
					+ constraintViolation.getMessage());
		}
	}
}</pre>
<p>Ce qui nous donne la sortie suivante dans la console :</p>
<pre class="brush:text">Première validation :
Nombre de violations : 1
Valeur 'http://www.blog.com/mon-article' incorrecte pour 'article' : L'article n'appartient pas au blog octo
Deuxième validation :
Nombre de violations : 0</pre>
<p>Notons qu&#8217;il nous était possible d&#8217;utiliser l&#8217;annotation <span style="color: #808080;">@Pattern</span> de la manière suivante :</p>
<pre class="brush:java">	@Pattern(regexp = "http://blog\\.octo\\.com/.*",
			message = "L'article n'appartient pas au blog octo")
	private String article;</pre>
<p>Une troisième façon de faire aurait été d&#8217;ajouter <span style="color: #808080;">@Pattern</span> en annotation de <span style="color: #808080;">@OctoBlog</span> :</p>
<pre class="brush:java">@Constraint(validatedBy = OctoBlogValidator.class)
@Target(value = ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Pattern(regexp = "http://blog\\.octo\\.com/.*")
@ReportAsSingleViolation
public @interface OctoBlog {

	String message() default "L'article n'appartient pas au blog octo";

	Class&lt;?&gt;[] groups() default {};

	Class&lt;? extends Payload&gt;[] payload() default {};
}</pre>
<p>L&#8217;annotation <span style="color: #808080;">@ReportAsSingleViolation</span> indique qu&#8217;il faut ignorer les messages d&#8217;erreur des annotations et qu&#8217;il faut utiliser le message défini dans <span style="color: #808080;">@OctoBlog</span>.<br />
&nbsp;</p>
<h3>Implémentation de référence : Hibernate Validator</h3>
<p>Pour exécuter les exemples précédents j&#8217;ai utilisé la version <em>4.2.0.Final</em> (disponible depuis juin 2011) d&#8217;<a href="http://www.hibernate.org/subprojects/validator" target="_blank">Hibernate Validator</a>, implémentation de référence de la JSR-303. En plus d&#8217;implémenter les annotations définies par la JSR, Hibernate Validator en ajoute des nouvelles comme <span style="color: #888888;">@Email</span>, <span style="color: #888888;">@NotEmpty</span> et <span style="color: #888888;">@CreditCardNumber</span>.</p>
<p>&nbsp;</p>
<h3>Autre implémentation : Apache Bean Validation</h3>
<p>Anciennement appelé <a href="http://code.google.com/p/agimatec-validation/" target="_blank">agimatec-validation</a>, ce projet est depuis mars 2010 en incubation chez apache : <a href="https://cwiki.apache.org/BeanValidation/" target="_blank">https://cwiki.apache.org/BeanValidation/</a> et la dernière version publiée est la <em>0.3-incubating</em>.</p>
<p>Pour tester cette implémentation, j&#8217;ai modifié les imports dans les exemples de la partie précédente. Le comportement obtenu était semblable à l&#8217;exception des messages d&#8217;erreur qui étaient en anglais. Bon point donc pour Hibernate qui a internationalisé les messages.</p>
<p>D&#8217;une manière générale, si vous voulez utiliser la JSR-303 pour valider les Beans dans vos projets, la préconisation est d&#8217;utiliser Hibernate Validator. En effet, cette implémentation est stable et les nouvelles releases sont assez régulières. Pour ceux qui veulent utiliser Apache Bean Validation, il est conseillé d&#8217;attendre que ce projet passe l&#8217;étape d&#8217;incubation.</p>
<p>Certains projets sont plutôt hésitants quant à l&#8217;utilisation de la validation au niveau des Beans Java craignant une baisse des performances générales. Pour avoir une idée du temps que prend la validation des objets, je vous conseille de regarder le benchmark publié <a href="http://carinae.net/2010/06/benchmarking-hibernate-validator-and-apache-beanvalidation-the-two-jsr-303-implementations/" target="_blank">ici</a> qui compare les temps nécessaires pour valider les Beans en utilisant les deux implémentations. Ce qui ressort de cette étude est que Apache Bean Validation <em>0.1-incubating</em> est plus performant que Hibernate Validator 4.1.0.CR1. Cependant ce benchmark a été réalisé en 2010 et depuis la version <em>4.2.0.Final</em> de Hiberante Validator est sortie, il serait donc intéressant de refaire les tests car cette dernière version est sensée améliorer les performances en diminuant les temps de validation.</p>
<p>&nbsp;</p>
<h3>GWT et la JSR-303</h3>
<p>Le framework <a href="http://code.google.com/p/gwt-validation/" target="_blank">gwt-validation</a> implémente  la JSR 303 et propose de valider les Beans aussi bien côté client que côté serveur. D&#8217;après le <a href="http://code.google.com/p/gwt-validation/wiki/GWT_Validation_2_0" target="_blank">wiki du projet</a> l&#8217;implémentation de la JSR est finie à 80%. Mais il ne sera bientôt plus obligatoire de passer par ce framework pour utiliser la JSR-303. En effet, depuis peu, Google a commencé à intégrer cette JSR dans GWT : <a href="http://code.google.com/p/google-web-toolkit/wiki/BeanValidation" target="_blank">http://code.google.com/p/google-web-toolkit/wiki/BeanValidation</a>. Cette intégration se base sur l&#8217;implémentation de référence Hibernate Validator et propose aussi une validation côtés serveur et client. Cette intégration n&#8217;est pas disponible dans GWT 2.3 mais l&#8217;est dans le trunk. Pour ceux qui veulent tester, un exemple d&#8217;utilisation est disponible <a href="http://code.google.com/p/google-web-toolkit/source/browse/trunk/samples/validation/src/com/google/gwt/sample/validation" target="_blank" class="broken_link">ici</a>. Il faut cependant faire attention car, comme annoncé sur la page du wiki du projet, la validation n&#8217;est pas encore mature et l&#8217;API peut encore beaucoup évoluer.</p>
<p>&nbsp;</p>
<h3>Conclusion : JSR-303 Vs le reste du monde</h3>
<p>Le besoin de valider les Beans Java est bien plus antérieur à la parution de JSR-303. En effet, d&#8217;autres frameworks se proposaient déjà de valider les objets comme <a href="http://commons.apache.org/validator/" target="_blank">Apache Commons Validator</a> dont la première release date de 2002. D&#8217;autres  frameworks Java embarquent leur propre mécanisme de validation comme Spring avec son <a href="http://static.springsource.org/spring/docs/2.0.x/reference/validation.html" target="_blank">Validator</a>. Pour utiliser ce dernier afin de valider notre classe Utilisateur, il aurait fallu créer une deuxième classe UtilisateurValidator qui implémente l&#8217;interface Validator de Spring.</p>
<p>Ces frameworks ayant été pensés à l&#8217;ère pré-JDK5, la JSR-303 simplifie la validation des Beans grâce à l&#8217;utilisation des annotations et rend le code plus lisible quant aux contraintes qu&#8217;il doit respecter. Elle apporte aussi un standard à cette partie très importante des projets informatiques que représente la validation des données.</p>

 <img src="http://blog.octo.com/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=22103" width="1" height="1" style="display: none;" /><p>Suggestion d'articles :</p><ol>
<li><a href='http://blog.octo.com/tests-unitaires-et-tests-d%e2%80%99interface-sur-iphone-etat-des-lieux/' rel='bookmark' title='Tests unitaires et tests d’interface sur iPhone : État des lieux'>Tests unitaires et tests d’interface sur iPhone : État des lieux</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://blog.octo.com/jsr-303-bean-validation-etat-des-lieux/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Comment ne plus avoir de NullPointerException en Java ?</title>
		<link>http://blog.octo.com/comment-ne-plus-avoir-de-nullpointerexception-en-java/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=comment-ne-plus-avoir-de-nullpointerexception-en-java</link>
		<comments>http://blog.octo.com/comment-ne-plus-avoir-de-nullpointerexception-en-java/#comments</comments>
		<pubDate>Mon, 22 Aug 2011 10:20:39 +0000</pubDate>
		<dc:creator>Rémy-Christophe Schermesser</dc:creator>
				<category><![CDATA[Architecture et technologies]]></category>
		<category><![CDATA[Brèves de consultants]]></category>
		<category><![CDATA[groovy]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[null]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[Scala]]></category>

		<guid isPermaLink="false">http://blog.octo.com/?p=24646</guid>
		<description><![CDATA[NullPointerException : l&#8217;erreur la plus courante dans un programme Java. On est tous à un moment ou à un autre tombé sur cette exception. Malheureusement, ce n&#8217;est qu&#8217;en production à 4h du matin qu&#8217;elle arrive. On corrige donc le bug suivant : MonObjet monObjet = null; … monObjet.maMethode(); // =&#62; NullPointerException Par un rapide : if(monObjet [...]
Suggestion d'articles :<ol>
<li><a href='http://blog.octo.com/article-parallelisation-distribution-partie-3-comment-tirer-parti-des-processeurs-multi-coeurs-a-travers-l-api-de-concurrence-de-java-7/' rel='bookmark' title='Parallélisation, distribution partie 3 : comment tirer parti des processeurs multi-coeurs à travers l&#8217;API de concurrence de Java 7 ?'>Parallélisation, distribution partie 3 : comment tirer parti des processeurs multi-coeurs à travers l&#8217;API de concurrence de Java 7 ?</a></li>
<li><a href='http://blog.octo.com/les-nouveautes-du-langage-dans-java-7/' rel='bookmark' title='Les nouveautés du langage dans Java 7'>Les nouveautés du langage dans Java 7</a></li>
<li><a href='http://blog.octo.com/un-dsl-sql-pour-java/' rel='bookmark' title='Un DSL SQL pour Java'>Un DSL SQL pour Java</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[
<div class="topsy_widget_data topsy_theme_blue" style="float: right;margin-left: 0.75em; background: url(data:,%7B%20%22url%22%3A%20%22http%253A%252F%252Fblog.octo.com%252Fcomment-ne-plus-avoir-de-nullpointerexception-en-java%252F%22%2C%20%22style%22%3A%20%22small%22%2C%20%22title%22%3A%20%22Comment%20ne%20plus%20avoir%20de%20NullPointerException%20en%20Java%20%3F%22%20%7D);"></div>
<p><em>NullPointerException</em> : l&#8217;erreur la plus courante dans un programme Java. On est tous à un moment ou à un autre tombé sur cette exception. Malheureusement, ce n&#8217;est qu&#8217;en production à 4h du matin qu&#8217;elle arrive. On corrige donc le bug suivant :</p>
<pre class="brush:java">MonObjet monObjet = null;
…
monObjet.maMethode(); // =&gt; NullPointerException</pre>
<p>Par un rapide :</p>
<pre class="brush:java">if(monObjet != null) {
  monObjet.maMethode();
}</pre>
<p>Ce correctif est tout à fait honorable, mais pourquoi ne pas essayer de ne plus avoir aucune exception de ce type ?</p>
<p>Il existe plusieurs méthodes validées par le compilateur pour l&#8217;éviter, et donc avant la mise en production. Aucune n&#8217;est nouvelle, certaines controversés, mais elles sont toutes étudiées dans la suite de cet article.</p>
<p><span id="more-24646"></span></p>
<h3>Tu n&#8217;utiliseras pas <em>null</em></h3>
<p>La première règle est simple : ne <strong>jamais</strong> utiliser le mot clé <em>null</em>.</p>
<p>Globalement, il est utilisé dans deux cas :</p>
<ul>
<li>initialisation d&#8217;objets</li>
<li>valeur vide</li>
</ul>
<p>Par exemple, au lieu d&#8217;écrire :</p>
<pre class="brush:java">String maVariable = null;

if(test == 0) {
  maVariable = "toto";
} else if(test &gt; 0) {
  maVariable = "titi";
} else {
  maVariable = "tata";
}

maVariable.subString(….)</pre>
<p>On peut tout simplement ne pas initialiser la variable <em>maVariable</em>. De cette façon, si on oublie un cas dans notre <em>if</em>, le compilateur va nous générer une erreur du type :</p>
<pre class="brush:bash">variable maVariable might not have been initialized</pre>
<p>Pour les valeurs vides, le problème est plus complexe. Nous verrons donc par la suite comme remplacer un <em>null </em>qui fait office de valeur vide.</p>
<h3>Tu utiliseras @NotNull, @Nullable</h3>
<p>La <a href="http://www.jcp.org/en/jsr/detail?id=308">JSR 308</a> nous apporte deux annotations <a href="http://www.jetbrains.com/idea/documentation/howto.html">@NotNull et @Nullable</a> qui permettent une vérification statique par le compilateur des valeurs des paramètres et de retour des méthodes. Par exemple :</p>
<pre class="brush:java">int maMethode(@NotNull String maChaine) {
  return maChaine.length();
}

maMethode(null);</pre>
<p>Dans ce cas on aurait eu une <em>NullPointerException</em> au lancement, alors qu&#8217;avec cette annotation on aura un <em>warning</em> directement à la compilation.</p>
<p>Bien évidement, mon exemple est simpliste mais cela fonctionne aussi sur des cas plus complexes.</p>
<p>Cette JSR peut être intégrée à plusieurs outils (Maven, Eclipse, etc.), pour plus de détails c&#8217;est <a href="http://types.cs.washington.edu/checker-framework/current/checkers-manual.html#external-tools">ici</a>. Il faut noter qu&#8217;IntelliJ l&#8217;intègre nativement.</p>
<h3>Tu utiliseras des objets vides</h3>
<p>Une autre façon d&#8217;éviter le <em>null </em>est d&#8217;utiliser le <a href="http://en.wikipedia.org/wiki/Null_Object_pattern">Null Object Pattern</a>. Le principe est très simple : créer des objets spécifiques qui représente le vide. Par exemple :</p>
<pre class="brush:java">class Personne {
  public String getNom() { … }
  public void setNom(String nom) { … }
  public List&lt;Personne&gt; getEnfants() { … }
}

public final PersonneVide extends Personne {
  public String getNom() {
    return "";
  }
  public void setNom(String nom) {}
  public List&lt;Personne&gt; getEnfants() {
    return Collections.emptyList();
  }
}</pre>
<p>Il suffit d&#8217;employer <em>PersonneVide</em> plutôt que d&#8217;utiliser <em>null. </em>Il y a plusieurs implémentations de cette solution. On peut aussi créer une interface <em>Personne</em> et l&#8217;implémenter en deux classe : <em>PersonnePhysique</em> (la vraie implémentation) et <em>PersonneVide</em>.</p>
<p>On peut aussi facilement étendre ce principe pour avoir d&#8217;autres objets plus spécifiques, comme le <a href="http://martinfowler.com/eaaCatalog/specialCase.html">montre</a> Martin Fowler.</p>
<p>Cette méthode a des nombreuses limitations. Il faut se contraindre à créer et surtout à utiliser ses objets vides. Ce qui rajoute du code et donc peut rajouter des bugs. À ma connaissance il n&#8217;existe pas de méthode automatique qui nous force à utiliser cette méthode.</p>
<h3>Tu lanceras des exceptions</h3>
<p>Une autre solution est d&#8217;utiliser des exceptions. Plutôt que de renvoyer une valeur <em>null</em>, on lance une exception. Cela à l&#8217;avantage d&#8217;avoir une validation statique faite par le compilateur. Pour plus de détail sur les bonnes pratiques sur la gestion des exceptions, c&#8217;est <a href="http://blog.octo.com/la-gestion-des-exceptions-en-java/">ici</a>. Par exemple :</p>
<pre class="brush:java">class ImpossibleDeGenererIDException extends Exception { … }

public class Personne {
  public Email genereID() throws ImpossibleDeGenererIDException {
    //On lance l'exception si on n'a pas pu générer d'ID
    //plutôt que de renvoyer null
  }
}</pre>
<p>Il faut noter que lancer une exception est très coûteux en terme de calcul. Et comme le dis très bien l&#8217;article citer ci-dessus, utiliser une exception pour un contrôle de flux est un anti-pattern. À mon avis, cette solution n&#8217;est pas à utiliser.</p>
<h3>Tu utiliseras le pattern <em>Option</em>/<em>Maybe</em></h3>
<p>Ce pattern nous vient des langages fonctionnels. Il consiste en un objet particulier <em>Option </em>qui encapsule un résultat. Cet objet peut avoir 2 valeurs possibles : une valeur non nulle (<em>Some</em>) ou <em>None</em>. Prenons un exemple de l&#8217;API de Java. La méthode <em>get </em>de <em>MyMap </em>renvoie <em>null</em> si l&#8217;objet demandé n&#8217;est pas présent dans celle-ci. Avec ce pattern, la méthode renverrait une instance d&#8217;<em>Option</em>. C&#8217;est donc l&#8217;utilisateur de la méthode est forcé par le compilateur de gérer le cas <em>None</em>. Une implémentation naïve serait donc :</p>
<pre class="brush:java">interface Option&lt;T&gt; {
  public Boolean isNone();
}

class Some&lt;T&gt; implements Option&lt;T&gt; {
  public T get() { … }
  public Boolean isNone() { return false; }
}

class None&lt;T&gt; implements Option&lt;T&gt; {
  public Boolean isNone() { return true; }
}

class MyMap&lt;K, V&gt; {
  public Option&lt;V&gt; get(K key) { … }
}

MyMap&lt;Integer, String&gt; map = new MyMap&lt;Integer, String&gt;();
map.put(1, "un");

Option&lt;String&gt; result = map.get(2);
if(result.isNone()) {
  // Gestion du cas None
} else {
  String val = ((Some) result).get();
}</pre>
<p>Cette méthode a le gros avantage d&#8217;avoir une validation statique par le compilateur. En effet, il est impossible d&#8217;utiliser directement la valeur de retour de la méthode <em>get</em>. Elle est du type <em>Option&lt;String&gt;</em> et donc complètement différent que celui attendu &laquo;&nbsp;classiquement&nbsp;&raquo; : <em>String. </em>On est donc forcé de faire le test du <em>None</em>. De plus, cela nous donne tout de suite l&#8217;information que la méthode peut renvoyer une valeur vide.</p>
<p>Cette implémentation est clairement bancale, la bibliothèque <a href="http://code.google.com/p/functionaljava">Functional Java</a> en fournit <a href="http://code.google.com/p/functionaljava/#Optional_Values_(type-safe_null)">une plus complète</a>.</p>
<p>C&#8217;est à mon avis la méthode la plus sûre. Mais elle a été pensée pour les langages gérant le <a href="http://fr.wikipedia.org/wiki/Filtrage_par_motif">pattern matching</a> comme <a href="http://www.scala-lang.org/">Scala</a> ou <a href="http://www.haskell.org/haskellwiki/Haskell">Haskell</a>, où elle est intégrée nativement dans l&#8217;API.</p>
<p>Elle est donc un peu lourde à utiliser en Java. Et surtout, elle n&#8217;est pas intégrée à l&#8217;API. Il faut donc soit utiliser une autre API, ou faire des wrapper autour de l&#8217;API standard.</p>
<h3>Conclusion</h3>
<p>Ces méthodes sont adaptables à tous les langages orientés objets. Certains offrent d&#8217;autres méthodes. Par exemple en Groovy il y a l&#8217;<a href="http://groovy.codehaus.org/Operators#Operators-OtherOperators">Elvis Operator</a>, en Ruby (avec Rails) le <a href="http://api.rubyonrails.org/classes/Object.html#method-i-try">try</a>.</p>
<p>Le problème reste lors de l&#8217;utilisation de bibliothèques externes. Même si un projet utilise ces solutions, il faudra toujours faire attention lors de l&#8217;utilisation de l&#8217;API Java ou autre (Hibernate pour ne citer que lui).</p>
<p>Il n&#8217;y a donc pas de méthode magique pour ne plus avoir de <em>NullPointerException</em> dans votre code Java (à part changer de langage ;)).</p>

 <img src="http://blog.octo.com/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=24646" width="1" height="1" style="display: none;" /><p>Suggestion d'articles :</p><ol>
<li><a href='http://blog.octo.com/article-parallelisation-distribution-partie-3-comment-tirer-parti-des-processeurs-multi-coeurs-a-travers-l-api-de-concurrence-de-java-7/' rel='bookmark' title='Parallélisation, distribution partie 3 : comment tirer parti des processeurs multi-coeurs à travers l&#8217;API de concurrence de Java 7 ?'>Parallélisation, distribution partie 3 : comment tirer parti des processeurs multi-coeurs à travers l&#8217;API de concurrence de Java 7 ?</a></li>
<li><a href='http://blog.octo.com/les-nouveautes-du-langage-dans-java-7/' rel='bookmark' title='Les nouveautés du langage dans Java 7'>Les nouveautés du langage dans Java 7</a></li>
<li><a href='http://blog.octo.com/un-dsl-sql-pour-java/' rel='bookmark' title='Un DSL SQL pour Java'>Un DSL SQL pour Java</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://blog.octo.com/comment-ne-plus-avoir-de-nullpointerexception-en-java/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Le Cloud au service de l&#8217;intégration continue</title>
		<link>http://blog.octo.com/le-cloud-au-service-de-integration-continue/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=le-cloud-au-service-de-integration-continue</link>
		<comments>http://blog.octo.com/le-cloud-au-service-de-integration-continue/#comments</comments>
		<pubDate>Tue, 02 Aug 2011 17:05:00 +0000</pubDate>
		<dc:creator>Vincent Canuel</dc:creator>
				<category><![CDATA[Architecture et technologies]]></category>
		<category><![CDATA[Cloud]]></category>
		<category><![CDATA[Continous Delevery]]></category>
		<category><![CDATA[Development As a Service]]></category>
		<category><![CDATA[intégration continue]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Université du SI]]></category>
		<category><![CDATA[Usine de développement]]></category>

		<guid isPermaLink="false">http://blog.octo.com/?p=24248</guid>
		<description><![CDATA[Il est bon de commencer par le pourquoi (c.f « start with Why » de Simon Sinek à l&#8217;USI 2011). En effet, pourquoi diable pousser le développement dans le Cloud ? Combien de temps me faut-il pour obtenir un environnement prêt à builder jours et nuits ? Combien de temps faut-il entre mon dernier build et la mise [...]
Suggestion d'articles :<ol>
<li><a href='http://blog.octo.com/platform-as-a-service-avec-ruby-on-rails/' rel='bookmark' title='Platform as a Service avec Ruby on Rails'>Platform as a Service avec Ruby on Rails</a></li>
<li><a href='http://blog.octo.com/integration-continue-performante-part-2/' rel='bookmark' title='Intégration continue performante (Part #2)'>Intégration continue performante (Part #2)</a></li>
<li><a href='http://blog.octo.com/5-minutes-pour-comment-faire-de-l-integration-continue-en-php/' rel='bookmark' title='5 minutes pour : Comment faire de l&#8217;intégration continue en PHP ?'>5 minutes pour : Comment faire de l&#8217;intégration continue en PHP ?</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[
<div class="topsy_widget_data topsy_theme_blue" style="float: right;margin-left: 0.75em; background: url(data:,%7B%20%22url%22%3A%20%22http%253A%252F%252Fblog.octo.com%252Fle-cloud-au-service-de-integration-continue%252F%22%2C%20%22style%22%3A%20%22small%22%2C%20%22title%22%3A%20%22%20Le%20Cloud%20au%20service%20de%20l%27int%C3%A9gration%20continue%22%20%7D);"></div>
<div>
<p dir="ltr">Il est bon de commencer par le pourquoi (c.f « <a href="http://www.universite-du-si.com/fr/conferences/8-paris-usi-2011/sessions/963-start-with-why">start with Why </a>» de Simon Sinek à l&#8217;USI 2011). En effet, pourquoi diable pousser le développement dans le Cloud ? Combien de temps me faut-il pour obtenir un environnement prêt à builder jours et nuits ? Combien de temps faut-il entre mon dernier build et la mise à disposition de mon application ? C’est pour répondre à ces problématiques que le passage à un modèle de « Development As A Service » prend tout son sens. Cet article s&#8217;inscrit dans la continuité de la réflexion d&#8217;OCTO sur ce thème, abordé lors de l’USI 2010 dans &laquo;&nbsp;<a href="http://www.universite-du-si.com/fr/conferences/6-usi-2010/sessions/918-opportunites-du-cloud-pour-la-direction-des-etudes">opportunités du Cloud pour la direction des Etudes</a>&nbsp;&raquo; .</p>
<p><span id="more-24248"></span></p>
<h1 dir="ltr">Le serveur d’intégration continue en mode SAAS</h1>
<p dir="ltr"><a href="http://blog.octo.com/integration-continue-performante-1/">Une intégration continue</a> réussie passe par un outillage riche et dont la disponibilité et l’extensibilité se doit être assurée et dont le serveur d’intégration en est le pilier. Une telle offre portée sur le Cloud apporterait un gain significatif pour l’IC en terme de <strong>rapidité de mise en place</strong>. En plus, selon les besoins on pourrait aisément enlever ou ajouter des instances (par exemple pour exécuter plus de builds en parallèle). Finalement, un tel service permettrait d’avoir une solution <strong>clé en main</strong>, avec pourquoi pas un écosystème de services, comme un outil de monitoring ou d’analyse de code, prêt à fonctionner d’un simple clic.</p>
<h1 dir="ltr">Les offres</h1>
<p dir="ltr">À première vue, c’est un terrain encore peu exploité mais deux offres émergent pour le monde Java, celle de <a href="http://www.cloudbees.com/">CloudBees</a> que nous étudierons plus tard et celle d’Atlassian nommée <a href="http://www.atlassian.com/hosted/studio/">Jira Studio</a>. Cette dernière propose une multitude de services qui sont transversaux pour la D.S.I car agissant du développeur au métier grâce à l’interaction entre bugtracker, suivi de tâche et moteur d’intégration.</p>
<p dir="ltr">À noter également que le monde .Net n’est pas en reste. En effet, Microsoft pourrait bientôt proposer une offre similaire avec Team Fundation Server sur Azure comme le montre un <a href="http://blogs.msdn.com/b/bharry/archive/2011/05/18/update-on-tfs-on-azure.aspx">post</a> sur le blog de l’un des membres de l’équipe TFS.</p>
<h1 dir="ltr">Retour d’expérience sur Cloudbees</h1>
<p dir="ltr">L’offre de CloudBees est séparée en deux parties, l’une réservée au développement (DEV@Cloud) et l’autre au déploiement (RUN@cloud). Dans la première, on a accès à des repositories (Maven, Git ou SVN) en lecture et écriture ainsi qu’à un serveur d’intégration (Jenkins), tout projets compilables sur celui-ci est donc accepté. Dans l’autre, on dispose d’une offre P.A.A.S simplifiée avec une base de données (MySQL) et un serveur d’application (Tomcat) qui ne supportera que des projets tournant sur une JVM. Voici un schéma montrant l’architecture des services proposés.</p>
<p style="text-align: center;"><img class="aligncenter size-full wp-image-24464" title="dev_run_arch" src="http://blog.octo.com/wp-content/uploads/2011/08/dev_run_arch.png" alt="" width="474" height="159" /></p>
<p dir="ltr">J’ai testé la solution « from scratch » pour compiler, tester et déployer un projet web à travers celui-ci. Il faut moins de 5 minutes, inscription comprise, pour accéder à un Dashboard avec l’ensemble des services « up &amp; ready».</p>
<p style="text-align: center;" dir="ltr"><img class="aligncenter size-full wp-image-24463" title="Capture d’écran 2011-06-24 à 10.00.08" src="http://blog.octo.com/wp-content/uploads/2011/08/Capture-d’écran-2011-06-24-à-10.00.08-e1312304301289.png" alt="" width="464" height="99" /></p>
<p style="text-align: left;">Pour mes tests, j’ai pris le projet open-source <a href="http://piglatin.buildndeploy.com/">PigWeb</a> (une application web de traduction). Après la phase de configuration, je lance mon premier build, celui-ci va être traité par un pool d’exécution et pousser les binaires vers mon référentiel privé.</p>
<p style="text-align: center;"><a href="http://blog.octo.com/wp-content/uploads/2011/08/screen3-e1312189648598.png"><img class="size-medium wp-image-24465 aligncenter" title="Configuration de Jenkins dans CloudBees" src="http://blog.octo.com/wp-content/uploads/2011/08/screen3-e1312189648598-300x155.png" alt="" width="300" height="155" /></a></p>
<p dir="ltr">Maintenant, je souhaite déployer mon application sur le Cloud et ainsi me rapprocher du monde du Continous delivery (c.f la <a href="http://www.universite-du-si.com/en/conferences/8-paris-usi-2011/sessions/967-continuous-delivery">présentation de Jez Humble à l’USI 2011</a>). Simple ! Je créé une instance sur RUN@cloud, j’active et configure le plugin intégré dans Jekins en indiquant simplement une clé et un mot de passe fourni par CloudBees. Enfin, je n’ai plus qu’à cocher et définir les fichiers qui doivent être déployés sur mon serveur d’application. On lance notre build et voilà :).</p>
<p style="text-align: center;" dir="ltr"><img class="aligncenter size-medium wp-image-24493" title="deploiement de pigweb dans CloudBees" src="http://blog.octo.com/wp-content/uploads/2011/08/deploy_pigweb-300x118.png" alt="" width="300" height="118" /></p>
<p dir="ltr">Finalement, de l’inscription aux tests fonctionnels de mon application il m’a fallu <strong>moins d’une heure</strong> et tout ceci gratuitement.</p>
<h1 dir="ltr">Pour aller plus loin&#8230;</h1>
<p dir="ltr">Quid de l&#8217;utilisation de notre UDD à la sauce CloudBees dans un contexte professionnel et/ou sécurisé ?</p>
<p dir="ltr">CloudBees ne propose pas de garantie ou SLA. De plus, comme tout SAAS sur un cloud public les<strong> instances sont mutualiséés</strong> et donc potentiellement plus vulnérables .</p>
<p dir="ltr">Cependant, l&#8217;accès au service nécessite une authentification, et les données sont privées aussi bien pour les référentiels que la base de données. Et pour aller plus loin CloudBees propose aussi des <a href="http://www.cloudbees.com/run-pe.cb">offres Pro</a>, l&#8217;une hébergée sur un Cloud Privé (= instances non mutualisées) en phase Beta pour le moment. L&#8217;autre, pour ceux qui ne veulent pas laisser sortir les données de leur infrastructure, sous la forme d&#8217;un Jenkins enrichi à déployer chez soi.</p>
<p dir="ltr"> D’autres services en S.A.A.S peuvent se greffer facilement <strong>à la manière de plugins </strong>comme du monitoring d’applications avec Web Relic (gratuit) ou encore de l’analyse de code avec Sonar (payant). Enfin, l&#8217;offre payante de CloudBees permet bien entendu d’ajouter des instances plus puissantes ou de l’espace disque.</p>
<h1 dir="ltr">Verdict</h1>
<p dir="ltr">Avec des outils tels que CloudBees, la mise en place d’une intégration continue devient un jeu d’enfant en apportant rapidité de mise en place et extensibilité. On peut même pousser un plus loin le développement dans le Cloud en codant directement dans un IDE en mode web comme le très prometteur <a href="http://blog.exoplatform.org/2011/07/20/the-top-5-new-features-in-exo-cloud-ide/">Exo-Ide</a> intégrant prochainement le support natif de CloudBees (ceci pourrait faire l’objet d’un prochain article). Alors&#8230; prêt pour développer dans le Cloud ?</p>
<h1>Liens utiles</h1>
<p>Java et CloudBees : <a href="http://javaadventure.blogspot.com/2011/05/continuously-deploy-your-java-apps-to.html">http://javaadventure.blogspot.com/2011/05/continuously-deploy-your-java-apps-to.html</a><br />
L’intégration Continue : <a href="http://continuousdelivery.com/2010/02/continuous-delivery/">http://continuousdelivery.com/2010/02/continuous-delivery/</a><br />
Cloud Computing : <a href="http://fr.wikipedia.org/wiki/Cloud_computing">http://fr.wikipedia.org/wiki/Cloud_computing</a><br />
Grails et CloudBees : <a href="https://malderhout.wordpress.com/2011/05/16/continuous-deployment-grails-apps-with-cloudbees-jenkins-github/">https://malderhout.wordpress.com/2011/05/16/continuous-deployment-grails-apps-with-cloudbees-jenkins-github/</a></p>
</div>

 <img src="http://blog.octo.com/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=24248" width="1" height="1" style="display: none;" /><p>Suggestion d'articles :</p><ol>
<li><a href='http://blog.octo.com/platform-as-a-service-avec-ruby-on-rails/' rel='bookmark' title='Platform as a Service avec Ruby on Rails'>Platform as a Service avec Ruby on Rails</a></li>
<li><a href='http://blog.octo.com/integration-continue-performante-part-2/' rel='bookmark' title='Intégration continue performante (Part #2)'>Intégration continue performante (Part #2)</a></li>
<li><a href='http://blog.octo.com/5-minutes-pour-comment-faire-de-l-integration-continue-en-php/' rel='bookmark' title='5 minutes pour : Comment faire de l&#8217;intégration continue en PHP ?'>5 minutes pour : Comment faire de l&#8217;intégration continue en PHP ?</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://blog.octo.com/le-cloud-au-service-de-integration-continue/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Socle technique des applications Java EE : dans le WAR ou dans le serveur ?</title>
		<link>http://blog.octo.com/socle-technique-des-applications-java-ee-dans-le-war-ou-dans-le-serveur/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=socle-technique-des-applications-java-ee-dans-le-war-ou-dans-le-serveur</link>
		<comments>http://blog.octo.com/socle-technique-des-applications-java-ee-dans-le-war-ou-dans-le-serveur/#comments</comments>
		<pubDate>Mon, 23 May 2011 20:00:41 +0000</pubDate>
		<dc:creator>Julien Jakubowski</dc:creator>
				<category><![CDATA[Architecture et technologies]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Java EE]]></category>
		<category><![CDATA[JBoss]]></category>

		<guid isPermaLink="false">http://blog.octo.com/?p=22945</guid>
		<description><![CDATA[Le sujet du packaging des applications Java EE a suscité récemment des échanges riches sur notre mailing-list interne. C&#8217;est pourquoi nous avons trouvé intéressant d&#8217;en publier une synthèse. Nous remercions Dominique Jocal pour avoir réalisé cette synthèse, ainsi que les participants à ce débat : Benoît Lafontaine, Mikael Robert, Bertrand Paquet, Marc Bojoly &#8211; et [...]
Suggestion d'articles :<ol>
<li><a href='http://blog.octo.com/les-nouveautes-du-langage-dans-java-7/' rel='bookmark' title='Les nouveautés du langage dans Java 7'>Les nouveautés du langage dans Java 7</a></li>
<li><a href='http://blog.octo.com/les-nouvelles-librairies-dans-java-7/' rel='bookmark' title='Les nouvelles librairies dans Java 7'>Les nouvelles librairies dans Java 7</a></li>
<li><a href='http://blog.octo.com/thrift-protobuf-compacite/' rel='bookmark' title='Thrift et Protocol Buffers : compacité du message sérialisé dans le monde Java'>Thrift et Protocol Buffers : compacité du message sérialisé dans le monde Java</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[
<div class="topsy_widget_data topsy_theme_blue" style="float: right;margin-left: 0.75em; background: url(data:,%7B%20%22url%22%3A%20%22http%253A%252F%252Fblog.octo.com%252Fsocle-technique-des-applications-java-ee-dans-le-war-ou-dans-le-serveur%252F%22%2C%20%22style%22%3A%20%22small%22%2C%20%22title%22%3A%20%22Socle%20technique%20des%20applications%20Java%20EE%20%3A%20dans%20le%20WAR%20ou%20dans%20le%20serveur%20%3F%22%20%7D);"></div>
<p><em>Le sujet du packaging des applications Java EE a suscité récemment des échanges riches sur notre mailing-list  interne. C&#8217;est pourquoi nous avons trouvé intéressant d&#8217;en publier une  synthèse. Nous remercions Dominique Jocal pour avoir  réalisé cette synthèse, ainsi que les participants à ce débat : Benoît  Lafontaine, Mikael Robert, Bertrand Paquet, Marc Bojoly &#8211; et nous vous  souhaitons une bonne lecture !</em></p>
<p>Un  projet de montée en version ou de changement de serveur d’application  Java et de JVM est l’occasion pour une direction technique de se pencher  à nouveau sur la stratégie d’empaquetage des applications : <strong> doivent-elles embarquer leur socle technique, ou s’appuyer sur celui présent dans le serveur d’application</strong> ?<br />
<span id="more-22945"></span></p>
<p>La  quasi-totalité des frameworks techniques utilisés par les applications  sont présents dans les serveurs récents. <strong>2 stratégies sont alors  possibles pour empaqueter les “webapps”</strong> (application web Java) :</p>
<ul>
<li>“<strong>full webapp</strong>”  : l’application embarque ses versions de frameworks techniques comme  SLF4J et LOG4J, Hibernate, CXF, iText&#8230;. Elle n’utilise du serveur  d’application &#8211; par ex. JBoss &#8211; que quelques services de connexions  HTTP, SQL, MOM, annuaire d’objet&#8230;</li>
<li>“<strong>full server</strong>”  : la webapp n’embarque que les frameworks absents du serveur, par  exemple iText. Elle utilise tous les autres frameworks techniques déjà  présents dans le serveur dans leurs versions présentes.</li>
</ul>
<p>Mettons-nous  dans un cas de portefeuille applicatif, au demeurant très courant: un  SI Java de plusieurs dizaines d’applications construites sur une  décennie, bâties sur 2 ou 3 générations de socles techniques &#8211; les  frameworks techniques d’injection, de logging, de persistance, d’IHM, de  génération PDF, etc &#8211; exécutées sur une seule machine virtuelle Java et  une seule version de serveur d’application sous licence/support  éditeur, sauf rares exceptions.<br />
Dans ce contexte également, citons les besoins et contraintes exprimés par les équipes techniques:</p>
<ul>
<li>Rester en phase avec l’évolution des serveurs d’applications qui embarquent toujours plus de services techniques.</li>
<li>Diminuer globalement l’effort d’intégration et de dépannage sur les frameworks techniques.</li>
<li>Continuer  à bénéficier au maximum des outils d’administration et de supervision  des ressources techniques, sans avoir à compenser en écrivant soi-même  ces outils.</li>
</ul>
<p>On peut être alors tenté pour ce cas d’adopter la stratégie “<strong>full server</strong>”:</p>
<ul>
<li><strong>on pourra toujours suivre l’évolution du serveur,</strong> pas de conflit avec les frameworks techniques embarqués en webapp;</li>
<li>la diminution voire la disparition de la diversité de frameworks <strong>rationalise de facto l’effort d’intégration et de dépannage</strong>;</li>
<li>la possibilité d’<strong>utiliser les outils fournis avec le serveur</strong> est par définition garantie.</li>
</ul>
<p>En revanche une <strong>contrainte</strong> apparaît: <strong>monter en version sur un framework technique</strong> pour résoudre un  problème ou gagner une fonctionnalité sur la moindre application  implique de <strong>mettre à niveau le serveur</strong>, <strong>la webapp n&#8217;est pas seule impactée</strong>.</p>
<p>Or les retours d’expérience montrent que cette contrainte a non seulement de grandes chances d’arriver, mais <strong>peut s’avérer bloquante</strong>.  Benoit, architecte Octo explique que “migrer ensemble toutes les  applications sur une version donnée est une mission quasi-imposssible”.  “L’application X subit le bug spécial de la version x.y.z qui n’est pas  compatible avec telle version de telle librairie, et à côté  l’application Y qui ne doit plus évoluer ne sera jamais compatible avec  cette fameuse version de librairie”. Fondamentalement, explique Marc,  “les cycles de vie des applis sont trop différents entre eux et encore  différents de celui d&#8217;une production”.</p>
<p>Enfin, il est possible de “rester en phase avec les évolutions des serveurs” en stratégie “full webapp” grâce à la notion de <strong>profil</strong>.  “Un profil très léger, avec uniquement un conteneur web et quelques  services d&#8217;administration” permet en même temps de disposer d’outillage  prêt à l’emploi pour l’Exploitation en laissant les webapps embarquer  des socles techniques plus importants. Un profil léger peut être obtenu  par exemple en utilisant un <a href="http://community.jboss.org/wiki/JBoss5xTuningSlimming">JBoss allégé</a>, ou en se contentant d’un simple conteneur de servlet comme Tomcat.</p>
<p>En conclusion, pour ce cas de SI, on préconise plutôt la <strong>stratégie “full webapp” sur serveur à profil léger</strong>. La webapp ne délègue alors au serveur un service technique que lorsque :</p>
<ul>
<li>il  vient avec un outillage prêt à l’emploi, différenciateur et  accélérateur pour la Production comme une configuration centralisée, une  reconfiguration à chaud&#8230;</li>
</ul>
<ul>
<li>l’API est mature et stable.</li>
</ul>
<p>L’accès  aux SGBDR, aux messageries applicatives, ou encore aux logs, sont des  exemples de tels services, si votre serveur d’applications dispose des  outils précités.<br />
Le  cas ou la strategie full-serveur pourrait être préconisée serait alors  sur un ensemble d&#8217;applications ayant le même cycle de vie et maintenues  par la même équipe.</p>

 <img src="http://blog.octo.com/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=22945" width="1" height="1" style="display: none;" /><p>Suggestion d'articles :</p><ol>
<li><a href='http://blog.octo.com/les-nouveautes-du-langage-dans-java-7/' rel='bookmark' title='Les nouveautés du langage dans Java 7'>Les nouveautés du langage dans Java 7</a></li>
<li><a href='http://blog.octo.com/les-nouvelles-librairies-dans-java-7/' rel='bookmark' title='Les nouvelles librairies dans Java 7'>Les nouvelles librairies dans Java 7</a></li>
<li><a href='http://blog.octo.com/thrift-protobuf-compacite/' rel='bookmark' title='Thrift et Protocol Buffers : compacité du message sérialisé dans le monde Java'>Thrift et Protocol Buffers : compacité du message sérialisé dans le monde Java</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://blog.octo.com/socle-technique-des-applications-java-ee-dans-le-war-ou-dans-le-serveur/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Vers des API haut niveau pour Java et NoSQL avec Spring Data</title>
		<link>http://blog.octo.com/vers-des-api-haut-niveau-pour-java-et-nosql-avec-spring-data/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=vers-des-api-haut-niveau-pour-java-et-nosql-avec-spring-data</link>
		<comments>http://blog.octo.com/vers-des-api-haut-niveau-pour-java-et-nosql-avec-spring-data/#comments</comments>
		<pubDate>Sun, 01 May 2011 14:47:03 +0000</pubDate>
		<dc:creator>Michel Domenjoud</dc:creator>
				<category><![CDATA[Actualité]]></category>
		<category><![CDATA[Architecture et technologies]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[NoSQL]]></category>
		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://blog.octo.com/?p=21389</guid>
		<description><![CDATA[A l&#8217;heure où les nouvelles technologies de stockage de données regroupées sous les termes NoSQL et Distributed Data Grid deviennent populaires, il est intéressant de suivre l&#8217;évolution de cet écosystème et notamment des librairies d&#8217;intégration avec ces outils. Des librairies apportant un certain niveau d&#8217;abstraction émergent, avec l&#8217;espoir de voir apparaître des solutions de haut niveau [...]
Suggestion d'articles :<ol>
<li><a href='http://blog.octo.com/data-grid-or-nosql-same-same-but-different-2/' rel='bookmark' title='Data Grid or nosql? same, same but different…'>Data Grid or nosql? same, same but different…</a></li>
<li><a href='http://blog.octo.com/rest-en-java-avec-la-jsr-311/' rel='bookmark' title='REST en JAVA avec la JSR-311'>REST en JAVA avec la JSR-311</a></li>
<li><a href='http://blog.octo.com/soiree-spring-au-paris-jug/' rel='bookmark' title='Soirée Spring au Paris JUG'>Soirée Spring au Paris JUG</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[
<div class="topsy_widget_data topsy_theme_blue" style="float: right;margin-left: 0.75em; background: url(data:,%7B%20%22url%22%3A%20%22http%253A%252F%252Fblog.octo.com%252Fvers-des-api-haut-niveau-pour-java-et-nosql-avec-spring-data%252F%22%2C%20%22style%22%3A%20%22small%22%2C%20%22title%22%3A%20%22Vers%20des%20API%20haut%20niveau%20pour%20Java%20et%20NoSQL%20avec%20Spring%20Data%22%20%7D);"></div>
<p>A l&#8217;heure où les nouvelles technologies de stockage de données regroupées sous les termes <strong>NoSQL </strong>et<strong> Distributed Data Grid</strong> deviennent populaires, il est intéressant de suivre l&#8217;évolution de cet écosystème et notamment des librairies d&#8217;intégration avec ces outils.<br />
Des librairies apportant un certain niveau d&#8217;abstraction émergent, avec l&#8217;espoir de voir apparaître des solutions de haut niveau comparables aux ORM que nous utilisons pour les bases relationnelles. Nous allons nous intéresser aujourd&#8217;hui au projet <strong>Spring Data</strong>, qui propose une certaine unification pour les accès aux bases de données dites NoSQL.<span id="more-21389"></span></p>
<h1>Spring Data</h1>
<p><a href="http://www.springsource.org/spring-data">Spring Data</a> est un projet en développement et lancé en 2010, visant à simplifier l&#8217;utilisation des bases NoSQL, des frameworks <a href="http://fr.wikipedia.org/wiki/MapReduce">Map-Reduce</a>, ou d&#8217;apporter des extensions pour le support des bases relationnelles. Le projet intègre aussi progressivement le framework <a href="http://redmine.synyx.org/projects/show/hades" target="_blank">Hades</a> qui <a href="http://www.infoq.com/articles/hades_jpa_repositories_done_right">apporte la notion de <em>repository</em> pour une approche Domain Driven Developpment</a>.</p>
<p>Spring Data regroupe déjà plusieurs sous-projets dédiés à des implémentations particulières :</p>
<ul>
<li>JPA, qui apporte de nouvelles fonctionnalités pour une approche DDD avec des bases relationnelles,</li>
<li>Graph, avec une implémentation pour Neo4j,</li>
<li>Document, avec une implémentation pour MongoDB,</li>
<li>Key &#8211; Value, des implémentations pour Redis et Riak,</li>
<li>Extensions JDBC.</li>
</ul>
<p>Dans l&#8217;ensemble, les projets existants consistent à apporter une couche d&#8217;abstraction facilitant la manipulation de données avec les différents systèmes de stockage. L&#8217;apport principal de ce projet est bien sûr de faciliter l&#8217;intégration de ces technologies à un applicatif Spring, et de profiter des facilités de configuration du framework : injection de beans, configuration xml et programmation orientée aspect.</p>
<p>Nous allons voir ce que peuvent apporter ces librairies par rapport à une utilisation directe des connecteurs existants. L&#8217;équipe prévoit également le support d&#8217;autres produits tels qu&#8217;Amazon S3, Cassandra ou Hadoop.</p>
<p>En parallèle, le projet <strong>Spring Data Mapping</strong>, actuellement hébergé côté Groovy, aurait pour objectif d&#8217;apporter une solution générique de mapping Objet-Base pour plusieurs bases NoSQL.</p>
<h2>Spring Data JPA et Domain-Driven-Developpment</h2>
<p>Une des vocations du projet Spring Data est d&#8217;apporter le support pour une approche <strong>Domain Driven Developpment (<em>DDD</em>)</strong> et l&#8217;utilisation du pattern <strong><a href="http://www.codeinsanity.com/2008/08/repository-pattern.html" target="_blank" class="broken_link">Repository</a></strong>. Spring Data JPA en est la première implémentation, dédiée aux bases relationnelles. Le projet est <a href="http://redmine.synyx.org/news/27">directement repris depuis le framework Hades</a>, dont les fonctionnalités sont progressivement intégrées au socle commun de Spring Data, et doit permettre à terme une approche DDD pour les différents types de stockage supportés.</p>
<h3>Génération de Repository</h3>
<p>Le développement d&#8217;un Repository est facilité en générant automatiquement les fonctions de CRUD les plus communes d&#8217;un service d&#8217;accès aux données :</p>
<ul>
<li>save</li>
<li>findById</li>
<li>findAll (avec gestion de résultats paginés)</li>
<li>count</li>
<li>delete</li>
<li>exists</li>
</ul>
<p>L&#8217;utilisation de l&#8217;API est plutôt simple, il suffit de définir son repository via une interface étendant l&#8217;interface JpaRepository de base, et le framework se chargera du reste.</p>
<pre class="brush:java">public interface PersonRepository extends JpaRepository&lt;Person, Long&gt; { … }</pre>
<p>De plus, l&#8217;API permet, comme cela se fait en Groovy et Rails, de générer les méthodes de requêtes à partir du nom de la méthode ou en utilisant une requête nommée (@NamedQuery). Par exemple, si on souhaite ajouter une méthode de recherche par nom à notre PersonRepository :</p>
<pre class="brush:java">public interface PersonRepository extends JpaRepository&lt;Person, Long&gt; {
 List&lt;Person&gt; findByLastname(String lastname);
}</pre>
<p>Le bean injecté par Spring comportera alors une méthode générée avec l&#8217;exécution de la requête correspondante : <em>&laquo;&nbsp;SELECT * FROM User WHERE lastname = ?&nbsp;&raquo;</em>.</p>
<p>La librairie permet principalement de réduire le volume de code à écrire lorsque l&#8217;on code un Repository, mais Spring Data JPA apporte d&#8217;autres fonctionnalités intéressantes:</p>
<ul>
<li>L&#8217;approche DDD est facilitée grâce aux supports des <strong>Specifications</strong>, qui utilisent des <em><a href="http://en.wikipedia.org/wiki/Closure_(computer_science)" target="_blank">closures</a> </em>pour définir des prédicats, tout en utilisant l&#8217;API Criteria de JPA2.</li>
</ul>
<pre class="brush:java">public static Specification isPersonMinor() {
	return new Specification() {
		Predicate toPredicate(Root root, CriteriaQuery<!--?--> query,
			CriteriaBuilder builder) {
			LocalDate date = new LocalDate().minusYears(18);
			return builder.lessThan(root.get(Person_.birthDate), date);
		}
	};
}</pre>
<ul>
<li>Ajout de fonctions pour la gestion des transactions au niveau <em>Repository</em></li>
<li>Entités auditables (suivi des dates et utilisateurs de création et modification). Il s&#8217;agit d&#8217;un sujet classique en entreprise lorsque le suivi des modifications de données est stratégique. Il sera intéressant de comparer cette fonctionnalité à son équivalent <a href="http://docs.jboss.org/envers/docs/index.html" target="_blank">Hibernate Envers</a>.</li>
<li>Support de la librairie <a href="http://www.querydsl.com/" target="_blank">Querydsl</a>.</li>
</ul>
<h2>Spring Data Graph</h2>
<p>Ce projet est dédié aux bases proposant une implémentation de type graphe et fournit une implémentation pour <a href="http://neo4j.org/">Neo4j</a>.<br />
Neo4j est une base de données graphe, qui répond également aux enjeux traditionnels d&#8217;une base de données (ACIDité des transactions, gestion des accès concurrents,rollback de transaction, haute disponibilité). Pour avoir un rapide tour d&#8217;horizon de ce qu&#8217;apporte une base de données graphe et plus particulièrement Neo4j, voir <a href="http://blog.xebia.fr/2010/05/03/nosql-europe-bases-de-donnees-graphe-et-neo4j/">ici</a>.</p>
<p>Spring Data Graph propose une véritable couche d&#8217;abstraction permettant un mapping entre un modèle objet utilisé dans l&#8217;application Java et les entités stockées physiquement dans la base graphe. Spring Data Graph définit donc les notions suivantes pour la modélisation au niveau des objets (les exemples proviennent de la <a href="http://static.springsource.org/spring-data/data-graph/docs/current/reference/html/" target="_blank">documentation officielle</a>, qui propose par ailleurs un exemple complet d&#8217;une application web utilisant les différents composants de Spring) :</p>
<ul>
<li>Annotations pour définir noeuds (@NodeEntity) et relations (@RelationshipEntity)</li>
<li>Gestion des index (@Indexed)</li>
</ul>
<pre class="brush:java">@NodeEntity
class Movie {
 @Indexed
 int id;

 String title;
 int year;    

 @RelatedTo(elementClass = Actor.class, type = "ACTS_IN", direction = Direction.INCOMING)
 Set&lt;Actor&gt; cast;

 @RelatedToVia(elementClass = Role.class, type = "ACTS_IN", direction = Direction.INCOMING)
 Iterable&lt;Role&gt; roles;
}

@NodeEntity
class Actor {    

 @Indexed
 int id;
 String name;

 @RelatedTo(elementClass = Movie.class, type = "ACTS_IN")
 Set&lt;Movie&gt; cast; 

 public Role playedIn(Movie movie, String roleName) {
 Role role = relateTo(movie, Role.class, "ACTS_IN");
 role.setRole(roleName);       
 return role;
 }
}

@RelationshipEntity
class Role {
 @EndNode
 Movie movie;

 @StartNode
 Actor actor;

 String role;
}</pre>
<ul>
<li>Utilisation du pattern Repository, avec des implémentations pour gérer des opérations de CRUD, index et recherches<em></em>; ainsi que les algorithmes de parcours de graphes.</li>
</ul>
<pre class="brush:java">GraphRepository&lt;Person&gt; graphRepository = graphRepositoryFactory.createGraphRepository(Person.class);</pre>
<p>Spring Graph apporte également une couche d&#8217;abstraction sur des aspects plus techniques, entre autres:</p>
<ul>
<li>Gérer des recherches:
<ul>
<li>en utilisant des algorithmes spécifiques de parcours de graphe (Traversal)</li>
<li>en utilisant le système de recherche indexée avec un moteur d&#8217;indexation séparé (Apache Lucene est inclus par défaut).</li>
</ul>
</li>
</ul>
<p>Pour cela, il suffit d&#8217;annoter le champ à indexer: @Indexed(fulltext = true, indexName = &laquo;&nbsp;search&nbsp;&raquo;), puis d&#8217;appeler la méthode findAllByQuery(indexedField, query))</p>
<ul>
<li>Gérer les transactions avec la configuration Spring standard et SpringTransactionManager</li>
<li>Gestion de la persistance des entités avec la méthode persist()</li>
<li>Validation de beans (JSR 303) via les annotations de définition de contraintes (@Min, @Max, @Size, @Email, &#8230;)</li>
</ul>
<h3>Définition d&#8217;entités <em>cross-store</em></h3>
<p>Un autre aspect très intéressant dans cette API est le <strong>support multi-base</strong> en définissant des <strong>entités partielles</strong>, qui permet d&#8217;utiliser plusieurs systèmes de stockage pour une même entité. Actuellement, il est possible de définir une entité dont une partie des champs sera géré via JPA dans une base relationnelle classique, tandis que l&#8217;autre partie est gérée dans une base de données graphe.</p>
<p>L&#8217;exemple suivant est une modélisation simpliste d&#8217;un système de vente dans lequel les articles et les ventes sont stockés dans une base relationnelle classique, hormis les liens entre les objets vendus (&laquo;&nbsp;Les acheteurs qui ont acheté ce produit ont également acheté&#8230;), ainsi que le total des ventes pour chaque article.</p>
<pre class="brush:java">@Entity
@Table(name = "product")
@NodeEntity(partial = true)
class Product {
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column(name = "id")
	private Long id;

	private String name;
	private String description
	private Double price;

	@GraphProperty
	Double totalSales;

	@RelatedTo(elementClass = Product.class, type = "SAME_SALE", direction = Direction.INCOMING)
	private Set&lt;Product&gt; linkedSales;

	@RelatedToVia(elementClass = SaleConnection.class, type = "SAME_SALE", direction = Direction.INCOMING)
	private Iterable&lt;SaleConnection&gt; salesConnections;

	@OneToMany
	private Set&lt;SoldItem&gt; sales;

	@Transactional
	public SaleConnection soldTogether(Product item) {
		SaleConnection connection = relateTo(item, SaleConnection.class, "SAME_SALE");
		connection.incrementLinkWidth();
		return connection;
	}
}

@RelationshipEntity
class SaleConnection {
	@EndNode
	Product item1;

	@StartNode
	Product item2;

	int linkWidth = 0;

	public void incrementLinkWidth(){
		linkWidth++;
	}
}

@Entity
@Table(name = "sales")
class SoldItem {
	@ManyToOne
	Product productReference;

	Double soldPrice;
}</pre>
<h2>Spring Data Document</h2>
<p>Ce projet est dédié aux bases proposant une implémentation de type document, et fournit pour l&#8217;instant une implémentation pour <a href="http://www.mongodb.org/">MongoDB</a>.</p>
<p>L&#8217;implémentation apporte une surcouche au client Java fourni par Mongo et en reproduit l&#8217;essentiel des fonctionnalités en s&#8217;intégrant au framework Spring, entre autres :</p>
<ul>
<li>Configuration Spring via XML ou classes @Configuration pour les instances Mongo et la gestion des replica set</li>
<li>MongoTemplate qui offre des mécanismes d&#8217;abstraction pour interagir avec MongoDB et pour gérer la persistance des objets Java avec MongoDB de manière transparente, la gestion des collections, exécuter des commandes shell internes.</li>
<li>Fonctions de recherche avec notamment :
<ul>
<li>possibilité d&#8217;utiliser des <em>Criteria</em></li>
<li>support des requêtes géographiques</li>
</ul>
<ul>
<li>gestion d&#8217;index</li>
</ul>
</li>
</ul>
<p>Par ailleurs, la librairie apporte le support du pattern Repository de manière similaire à Spring Data JPA  avec MongoRepository:</p>
<ul>
<li>Génération des fonctions de CRUD</li>
<li>Gestion de requêtes prédéfinies au format JSON, par exemple:</li>
</ul>
<pre class="brush:java">public interface PersonRepository extends MongoRepository&lt;Person, String&gt;
  @Query("{ 'firstname' : ?0 }")
  List&lt;Person&gt; findByThePersonsFirstname(String firstname);
}</pre>
<ul>
<li>Support de Querydsl</li>
</ul>
<p>Enfin, la dernière version fraichement sortie de l&#8217;API propose d&#8217;une part un système de mapping à base d&#8217;annotations, avec notamment la possibilité de gérer les collections au sein d&#8217;un document par référence ou non:</p>
<pre class="brush:java">@Document
public class Account {
  @Id
  private ObjectId id;
  private Float total;
}

@Document
public class Person {
  @Id
  private ObjectId id;
  @Indexed
  private Integer ssn;
  @DBRef
  private List&lt;Account&gt; accounts;
}</pre>
<p>D&#8217;autre part, cette dernière release apporte comme l&#8217;API Graph un support <em>cross-store persistence</em>, permettant d&#8217;utiliser conjointement plusieurs systèmes de stockage de données.</p>
<p>Cette librairie semble plutôt aboutie et vient sans doute concurrencer sérieusement les librairies existantes comme <a href="http://code.google.com/p/morphia/">Morphia</a>, qui propose également des fonctions de mapping notamment.</p>
<h2>Spring Data Key-Value</h2>
<p>Le projet Key-Value (SDKV) est dédié aux bases proposant une implémentation clé-valeurs, et fournit des implémentations pour <a href="http://redis.io/">Redis</a> et <a href="http://wiki.basho.com/">Riak</a>.</p>
<p>Il s&#8217;agit pour l&#8217;instant essentiellement d&#8217;une couche d&#8217;abstraction au dessus des librairies de bas niveau existantes, qui permet principalement de tirer avantage d&#8217;une configuration Spring. Ces deux librairies semblent encore à un niveau de  maturité assez faible et n&#8217;apportent pour l&#8217;instant pas beaucoup par rapport à une utilisation directe des connecteurs.</p>
<h3>Redis</h3>
<p>L&#8217;implémentation SDKV pour Redis est une surcouche aux connecteurs Jedis, JRedis et RJC, qui apporte notamment:</p>
<ul>
<li>Configuration simple via XML, par exemple :</li>
</ul>
<pre class="brush:xml">&lt;bean id="jedisConnectionFactory" class="org.springframework.data.keyvalue.redis.connection.jedis.JedisConnectionFactory"&gt;
	&lt;property name="hostName" value="localhost"/&gt;
	&lt;property name="port" value="6379"/&gt;
	&lt;property name="timeout" value="5000"/&gt;
	&lt;property name="pooling" value="true"/&gt;
&lt;/bean&gt;

&lt;bean id="redisTemplate" class="org.springframework.data.keyvalue.redis.core.RedisTemplate"
	p:connection-factory-ref="jedisConnectionFactory"/&gt;</pre>
<ul>
<li>Utilisation d&#8217;objets plutôt que de dialoguer directement avec Redis grâce à la classe RedisTemplate
<ul>
<li>classes correspondant aux opérations de Redis (Value, List, Set, ZSet, Hash et Bound*)</li>
<li>fonctions de messaging (Send/Publish/Subscribe)</li>
</ul>
</li>
<li>Possibilité d&#8217;utiliser différents mécanismes de sérialisation pour stocker des objets</li>
</ul>
<p>Plusieurs articles on déjà été publiés sur le sujet:</p>
<ul>
<li><a href="http://pietrowski.info/2011/01/spring-data-redis-tutorial/">SpringData &#8211; Redis tutorial</a></li>
<li><a href="http://java.dzone.com/articles/movie-recommendation-app-using">Movie Recommendation App using Spring Data and Redis</a></li>
<li><a href="http://java.dzone.com/articles/creating-an-application-using-spring-data-with-redis-as-datastore-part-1">Creating an Application using Spring Data with Redis as Datastore &#8212; Part 1</a></li>
<li><a href="https://github.com/SpringSource/spring-data-keyvalue-examples">Exemples sur le github de SpringSource</a></li>
</ul>
<h3>Riak</h3>
<p>Là aussi, SDKV propose une surcouche au client Java développé par Basho (la société derrière Riak). Une base de données Riak est nativement accédée via une API REST/HTTP, utilisant les drivers Apache Commons.</p>
<p>La librairie apporte notamment :</p>
<ul>
<li>Configuration simple par XML, par exemple:</li>
</ul>
<pre class="brush:xml">&lt;bean id="riakTemplate"
      p:defaultUri="http://localhost:8098/riak/{bucket}/{key}"
      p:mapReduceUri="http://localhost:8098/mapred"/&gt;</pre>
<ul>
<li>Utilisation d&#8217;objets plutôt que de dialoguer directement avec Riak grâce à la classe RiakTemplate
<ul>
<li>pour les fonctions d&#8217;accès et de stockage</li>
<li>l&#8217;utilisation de l&#8217;algorithme Map/Reduce</li>
<li>les fonction de liaison entre les entrées et de parcours des listes liées</li>
</ul>
</li>
<li>Gestion asynchrone des échanges avec la base de données avec des <em>callbacks</em></li>
<li>Utilisation de services personnalisés de conversion d&#8217;objets vers Riak ou de ClassLoader depuis Riak</li>
</ul>
<h2>Spring Data JDBC Extensions</h2>
<p>Cette partie de Spring Data se situe un peu en marge du reste car il s&#8217;agit ici de fournir des extensions de configuration spécifiques à certaines implémentations de bases de données relationnelles.</p>
<p>La première version du projet comporte des extensions pour les bases de données Oracle, qui constituent un portage du code d&#8217;un module auparavant payant de Spring, le <a href="http://www.springsource.org/node/617" target="_blank">Advanced Pack for Oracle Database</a>. Cette extension doit notamment permettre un support transparent pour les applications de fonctionnalités telles que le <em>Fast Connection Failover</em> d&#8217;Oracle RAC, Advanced Queuing, et des types de données complexes (XML, STRUCT, ARRAY).</p>
<h2>Vers une abstraction de plus haut niveau?</h2>
<h3>Spring Data Mapping</h3>
<p>Ce dernier projet plutôt ambitieux vise à fournir un framework mutualisé de mapping objet pour les différents implémentations de stockage de données. C’est finalement une surcouche aux projets précédents qui cherche, j’imagine, à décorréler la modélisation du stockage physique. A l&#8217;heure actuelle, le projet est simplement mentionné dans la page du projet Spring Data, il n&#8217;y a pas de version SNAPSHOT disponible. Le projet est pour l&#8217;instant en Groovy, mais devrait être migré en Java pour s&#8217;intégrer à Spring Data.</p>
<p>D&#8217;après ce qu&#8217;on peut voir des sources existantes, il serait bien possible de définir un mapping d&#8217;objets de manière relativement  indépendante de la base de données : on trouve un projet core, et des implémentations pour de nombreuses technologies: Gemfire, Hibernate, AppEngine, Redis, Mongo, Cassandra et d&#8217;autres&#8230;</p>
<h3>Hibernate OGM</h3>
<p><a href="http://community.jboss.org/wiki/OverviewofHibernateOGM">Hibernate OGM</a> est un projet démarré en juillet 2010 et mené par <a href="http://twitter.com/emmanuelbernard" target="_blank">Emmanuel Bernard</a> chez JBoss. Le projet a été repris d&#8217;un essai d&#8217;une implémentation JPA-like pour <a href="http://www.slideshare.net/maniksurtani/infinspan-inmemory-data-grid-meets-nosql">Infinispan</a>, le moteur de grille de données open source de JBoss. A l&#8217;heure actuelle, le projet semble être à un stade plutôt expérimental et bien moins avancé que Spring Data, mais il sera intéressant de suivre son évolution et l&#8217;orientation qui sera suivie, car les deux projets seront sans doute concurrents.</p>
<p>Concrètement, Hibernate OGM souhaite utiliser Hibernate Core pour stocker des données dans une grille de données distribuée, en l&#8217;occurrence Infinispan. L&#8217;objectif est de réutiliser l&#8217;implémentation existante de JPA plutôt que de repartir de zéro, pour mapper des entités et des relations.</p>
<h1>Pour conclure</h1>
<p>Pour l&#8217;instant, en dehors de l&#8217;API Graph, Spring Data est en cours de développement et il n&#8217;est donc pas encore question d&#8217;utiliser ces librairies en production. Néanmoins, l&#8217;avancement actuel des différentes librairies laisse déjà présager de plusieurs atouts à leur utilisation :</p>
<ul>
<li><strong>intégration au framework Spring</strong> et apport de ses facilités de configuration.</li>
<li><strong>abstraction</strong> par rapport aux implémentations des différentes solutions de stockage NoSQL et <strong>apport de surcouches aux connecteurs</strong>, notamment grâce aux systèmes de mapping par <strong>annotations</strong>. Il y a encore du travail sur ce point pour offrir toutes les fonctionnalités de chaque base de données et y gagner réellement par rapport à l&#8217;utilisation d&#8217;une API de plus bas niveau.</li>
<li>développement facilité dans une <strong>approche orientée Domain-Driven-Developpment</strong>.</li>
</ul>
<p>Mais la perspective la plus intéressante est l&#8217;émergence de solutions unifiées de mapping objet/base permettant de limiter les spécificités à chaque base. Spring Data et Hibernate OGM ont un potentiel intéressant car ils ouvrent la voie vers une abstraction de plus haut niveau pour des implémentations et surtout des concepts de stockage de données très divers.</p>
<p>En s&#8217;attaquant à ces problématiques de mutualisation, ces projets attaquent la question complexe des frontières entre ces différents concepts :</p>
<ul>
<li><strong>Peut-on espérer avoir une abstraction suffisante pour passer d&#8217;une manière transparente d&#8217;une implémentation relationnelle à certains modes de stockage NoSQL?</strong></li>
</ul>
<p>Spring Data tente d&#8217;adresser ce problème avec le socle commun du framework et le projet Spring Data Mapping, de même qu&#8217;Hibernate OGM en réutilisant Hibernate Core pour Infinispan. Mais il faudra être très prudent sur ce point et ne pas tomber dans le piège de vouloir faire du relationnel classique dans une base clé-valeur ou document par exemple, en risquant de perdre les avantages de ces représentations.</p>
<ul>
<li><strong>Dans quelle mesure peut-on outiller les développements pour utiliser conjointement et de manière transparente plusieurs systèmes de représentation des données?</strong></li>
</ul>
<p>Dans ce sens, Spring Data adresse directement cette frontière, avec la notion d&#8217;entités partielles pour l&#8217;API Graph : une même application peut être amené à utiliser plusieurs techniques de stockage conjointement, et nous avons besoin d&#8217;outils pour faciliter ces développements.</p>
<p>Finalement, les deux projets étudiés ici adressent un point essentiel : le mouvement NoSQL ne propose pas simplement de nouvelles techniques de stockage, mais vise surtout à adresser les solutions adaptées à chaque problème, en arguant le fait qu&#8217;il n&#8217;existe pas de solution unique parfaite.</p>
<p>L&#8217;écosystème autour de NoSQL et du stockage distribué est bien vivant, et surtout il est bien parti pour gagner en maturité et en accessibilité pour les développements Java. On suivra donc avec attention la sortie des premières versions définitives!</p>

 <img src="http://blog.octo.com/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=21389" width="1" height="1" style="display: none;" /><p>Suggestion d'articles :</p><ol>
<li><a href='http://blog.octo.com/data-grid-or-nosql-same-same-but-different-2/' rel='bookmark' title='Data Grid or nosql? same, same but different…'>Data Grid or nosql? same, same but different…</a></li>
<li><a href='http://blog.octo.com/rest-en-java-avec-la-jsr-311/' rel='bookmark' title='REST en JAVA avec la JSR-311'>REST en JAVA avec la JSR-311</a></li>
<li><a href='http://blog.octo.com/soiree-spring-au-paris-jug/' rel='bookmark' title='Soirée Spring au Paris JUG'>Soirée Spring au Paris JUG</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://blog.octo.com/vers-des-api-haut-niveau-pour-java-et-nosql-avec-spring-data/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Audit avec JPA : date de création et de dernière mise à jour</title>
		<link>http://blog.octo.com/audit-avec-jpa-date-de-creation-et-de-derniere-mise-a-jour/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=audit-avec-jpa-date-de-creation-et-de-derniere-mise-a-jour</link>
		<comments>http://blog.octo.com/audit-avec-jpa-date-de-creation-et-de-derniere-mise-a-jour/#comments</comments>
		<pubDate>Tue, 26 Apr 2011 05:00:20 +0000</pubDate>
		<dc:creator>Marc Bojoly</dc:creator>
				<category><![CDATA[Architecture et technologies]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[JPA]]></category>

		<guid isPermaLink="false">http://blog.octo.com/?p=21328</guid>
		<description><![CDATA[Lorsqu&#8217;on écrit une application avec des données persistantes, il est souvent nécessaire de pouvoir réaliser de l&#8217;audit sur les modifications. Aujourd&#8217;hui, l&#8217;état de l&#8217;art pour la persistance des données se base sur des outils de type ORM à travers l&#8217;interface JPA en Java. Etre capable d&#8217;ajouter à chaque table la date de création et de [...]
Suggestion d'articles :<ol>
<li><a href='http://blog.octo.com/tours-jug-apache-maven-mise-en-uvre-en-entreprise/' rel='bookmark' title='Tours JUG &#8211; Apache Maven, mise en œuvre en entreprise'>Tours JUG &#8211; Apache Maven, mise en œuvre en entreprise</a></li>
<li><a href='http://blog.octo.com/le-jour-ou-la-documentation-a-disparu/' rel='bookmark' title='Le jour où la documentation a disparu'>Le jour où la documentation a disparu</a></li>
<li><a href='http://blog.octo.com/mon-action-lean-du-jour/' rel='bookmark' title='Mon action lean du jour'>Mon action lean du jour</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[
<div class="topsy_widget_data topsy_theme_blue" style="float: right;margin-left: 0.75em; background: url(data:,%7B%20%22url%22%3A%20%22http%253A%252F%252Fblog.octo.com%252Faudit-avec-jpa-date-de-creation-et-de-derniere-mise-a-jour%252F%22%2C%20%22style%22%3A%20%22small%22%2C%20%22title%22%3A%20%22Audit%20avec%20JPA%20%3A%20date%20de%20cr%C3%A9ation%20et%20de%20derni%C3%A8re%20mise%20%C3%A0%20jour%22%20%7D);"></div>
<p>Lorsqu&#8217;on écrit une application avec des données persistantes, il est souvent nécessaire de pouvoir réaliser de l&#8217;audit sur les modifications. Aujourd&#8217;hui, l&#8217;état de l&#8217;art pour la persistance des données se base sur des outils de type ORM à travers l&#8217;interface JPA en Java. Etre capable d&#8217;ajouter à chaque table la date de création et de dernière mise à jour est souvent la première demande en terme d&#8217;audit. Borémi et moi avons du répondre à cette question en mission. Nous avons regroupé et étudié différentes implémentations, notamment mises en oeuvre par d&#8217;autres Octos. De façon à vous aider à choisir le meilleur outil dans ce genre de situation, je vais vous présenter dans <a href="http://blog.octo.com/en/audit-with-jpa-creation-and-update-date/">cet article (en anglais)</a> les différentes solutions que nous avons comparées.<br />
<span id="more-21328"></span></p>

 <img src="http://blog.octo.com/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=21328" width="1" height="1" style="display: none;" /><p>Suggestion d'articles :</p><ol>
<li><a href='http://blog.octo.com/tours-jug-apache-maven-mise-en-uvre-en-entreprise/' rel='bookmark' title='Tours JUG &#8211; Apache Maven, mise en œuvre en entreprise'>Tours JUG &#8211; Apache Maven, mise en œuvre en entreprise</a></li>
<li><a href='http://blog.octo.com/le-jour-ou-la-documentation-a-disparu/' rel='bookmark' title='Le jour où la documentation a disparu'>Le jour où la documentation a disparu</a></li>
<li><a href='http://blog.octo.com/mon-action-lean-du-jour/' rel='bookmark' title='Mon action lean du jour'>Mon action lean du jour</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://blog.octo.com/audit-avec-jpa-date-de-creation-et-de-derniere-mise-a-jour/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

