<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>Blog Excilys</title>
	
	<link>http://blog.excilys.com</link>
	<description>Langages, Architectures &amp; Méthodologies</description>
	<lastBuildDate>Mon, 26 Jul 2010 12:55:55 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/blogexcilyscom" /><feedburner:info uri="blogexcilyscom" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>Oubliez les redéploiements grâce à JRebel</title>
		<link>http://feedproxy.google.com/~r/blogexcilyscom/~3/aSDOZsFqkys/</link>
		<comments>http://blog.excilys.com/2010/07/15/oubliez-les-redeploiements-grace-a-jrebel/#comments</comments>
		<pubDate>Thu, 15 Jul 2010 21:10:39 +0000</pubDate>
		<dc:creator>Bastien JANSEN</dc:creator>
				<category><![CDATA[Non classé]]></category>
		<category><![CDATA[classloader]]></category>
		<category><![CDATA[déploiement]]></category>
		<category><![CDATA[hotswapping]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[jrebel]]></category>
		<category><![CDATA[JVM]]></category>
		<category><![CDATA[performances]]></category>

		<guid isPermaLink="false">http://blog.excilys.com/?p=2430</guid>
		<description><![CDATA[Introduction
Comme une grande partie des lecteurs de ce blog, vous avez certainement déjà travaillé sur des applications web Java EE de taille variable, sur lesquelles vous avez fait un nombre indécent de redéploiements à chaque fois que vous vouliez valider des modifications fraîchement apportées. Puis vous avez dû découvrir que depuis Java 1.4, la JVM [...]]]></description>
			<content:encoded><![CDATA[<h3>Introduction</h3>
<p>Comme une grande partie des lecteurs de ce blog, vous avez certainement déjà travaillé sur des applications web Java EE de taille variable, sur lesquelles vous avez fait un nombre indécent de redéploiements à chaque fois que vous vouliez valider des modifications fraîchement apportées. Puis vous avez dû découvrir que depuis Java 1.4, la JVM permet de faire du <a href="http://download.oracle.com/docs/cd/E17476_01/javase/1.4.2/docs/guide/jpda/enhancements.html#hotswap"><em>Hotswap </em> en mode debug</a>, c&#8217;est-à-dire de remplacer du code à la volée au runtime.<br />
<span id="more-2430"></span><br />
C&#8217;est bien, mais il y a quand même des limitations : on ne peut que modifier le corps d&#8217;une méthode déjà existante, si l&#8217;on ajoute une méthode ou une classe elle ne sera pas prise en compte. Idem pour les membres statiques, les annotation ou encore les fichiers properties accédés via un ResourceBundle.</p>
<p>C&#8217;est pour pallier ces manques que la société Estonienne <a href="http://www.zeroturnaround.com/">ZeroTurnaround</a> a développé <a href="http://www.zeroturnaround.com/jrebel/">JRebel</a>, un outil destiné aux développeurs désirant <strong>gagner du temps</strong> dans leur cycle de développement.</p>
<h3>JRebel, c&#8217;est quoi ?</h3>
<p>Comme l&#8217;explique en anglais un <a href="http://www.zeroturnaround.com/blog/reloading_java_classes_401_hotswap_jrebel/">article du blog de ZeroTurnaround</a>, JRebel est principalement un agent à installer dans votre serveur d&#8217;applications, qui va réagir à des mises à jour de classes, ou plus généralement de ressources composant votre application. À l&#8217;aide d&#8217;un fichier de configuration rebel.xml, vous allez spécifier une liste de ressources à surveiller, par exemple des répertoires contenant des JAR et des fichiers properties. Lors du déploiement de votre application, l&#8217;agent va utiliser cette configuration pour scruter des changements dans ces répertoires (un timestamp plus récent).</p>
<p>Pour appliquer ces changements, JRebel introduit un <a href="http://en.wikipedia.org/wiki/Java_Classloader">classloader</a> qui va se charger de détecter le chargement des classes, pour ensuite générer des classes anonymes grâce la génération de bytecode <em>on-the-fly</em>. À chaque modification d&#8217;une classe dans votre IDE, une nouvelle classe anonyme sera générée pour modifier le comportement de la classe originale, grâce à un savant mélange de JIT et de magie noire (l&#8217;article ne rentre pas trop dans les détails du fonctionnement interne, secret de fabrication oblige puisque c&#8217;est un outil commercial).</p>
<div id="attachment_2431" class="wp-caption aligncenter" style="width: 560px"><a href="http://blog.excilys.com/wp-content/uploads/2010/07/jrebel-agent.png"><img class="size-full wp-image-2431" title="Fonctionnement de l'agent" src="http://blog.excilys.com/wp-content/uploads/2010/07/jrebel-agent.png" alt="" width="550" height="329" /></a><p class="wp-caption-text">Fonctionnement de l&#39;agent (image issue du site de ZeroTurnaround)</p></div>
<p>Au final, la perte de performances est minimisée comparé au gain de temps entrainé par le fait que l&#8217;on ne soit pas obligé de redéployer toutes les 5 minutes. Que vous utilisiez des JAR, des WAR, du Spring, Struts, Wicket ou autre Hibernate, sur des serveurs Glassfish, Websphere, JBoss, ou encore Weblogic, il y a de fortes chances que <a href="http://www.zeroturnaround.com/jrebel/comparison/">JRebel le supporte</a> de base ou via des plugins. Et si votre framework favori n&#8217;est pas dans la liste, une API vous permet de <a href="http://www.zeroturnaround.com/jrebel/plugins/">développer votre propre plugin</a>.</p>
<h3>Mise en pratique</h3>
<h4>Cas simple : modification d&#8217;une méthode</h4>
<p>Nous allons maintenant tester JRebel sur une application web type HelloWorld. Comme je l&#8217;ai déjà dit plus haut, c&#8217;est un outil commercial mais une version d&#8217;évaluation de 30 jours est <a href="http://www.zeroturnaround.com/jrebel/current/">disponible sur le site</a>. L&#8217;installation est très bien expliquée par un wizard prenant en compte votre IDE et votre serveur, donc je ne m&#8217;attarderai pas sur le sujet.</p>
<p>J&#8217;ai choisi d&#8217;utiliser Netbeans et Glassfish pour déployer une application toute simple : une calculatrice. Je dispose d&#8217;une servlet nommée Calculator, chargée de faire des additions et des soustractions :</p>
<pre>
<div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;height:300px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br /></div></td><td><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> Calculator <span style="color: #000000; font-weight: bold;">extends</span> HttpServlet <span style="color: #009900;">&#123;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">protected</span> <span style="color: #000066; font-weight: bold;">void</span> processRequest<span style="color: #009900;">&#40;</span>HttpServletRequest request, HttpServletResponse response<span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">throws</span> ServletException, <span style="color: #003399;">IOException</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; response.<span style="color: #006633;">setContentType</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;text/html;charset=UTF-8&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003399;">String</span> operation <span style="color: #339933;">=</span> request.<span style="color: #006633;">getParameter</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;operation&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003399;">Integer</span> result <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>operation <span style="color: #339933;">!=</span> <span style="color: #000066; font-weight: bold;">null</span> <span style="color: #339933;">&amp;&amp;</span> request.<span style="color: #006633;">getParameter</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;a&quot;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">!=</span> <span style="color: #000066; font-weight: bold;">null</span> <span style="color: #339933;">&amp;&amp;</span> request.<span style="color: #006633;">getParameter</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;b&quot;</span><span style="color: #009900;">&#41;</span> <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><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003399;">Integer</span> a <span style="color: #339933;">=</span> <span style="color: #003399;">Integer</span>.<span style="color: #006633;">valueOf</span><span style="color: #009900;">&#40;</span>request.<span style="color: #006633;">getParameter</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;a&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003399;">Integer</span> b <span style="color: #339933;">=</span> <span style="color: #003399;">Integer</span>.<span style="color: #006633;">valueOf</span><span style="color: #009900;">&#40;</span>request.<span style="color: #006633;">getParameter</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;b&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>operation.<span style="color: #006633;">equals</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;add&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; result <span style="color: #339933;">=</span> a <span style="color: #339933;">+</span> b<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">else</span> <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>operation.<span style="color: #006633;">equals</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;sub&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; result <span style="color: #339933;">=</span> a <span style="color: #339933;">-</span> b<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">else</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">throw</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">IllegalArgumentException</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Don't fool me, use correct parameters: a, b and operation!!&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003399;">PrintWriter</span> out <span style="color: #339933;">=</span> response.<span style="color: #006633;">getWriter</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">try</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; out.<span style="color: #006633;">println</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;The result is &quot;</span> <span style="color: #339933;">+</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span>result <span style="color: #339933;">==</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">?</span> <span style="color: #0000ff;">&quot;unpredictable&quot;</span> <span style="color: #339933;">:</span> result<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">finally</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; out.<span style="color: #006633;">close</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div>
</pre>
<p>Attention, Netbeans est malin et par défaut fait du <em>deploy-on-save</em>. Il faut donc désactiver l&#8217;option dans les propriétés du projet pour ne pas interférer avec JRebel.</p>
<p>La configuration du fichier rebel.xml, à placer dans WEB-INF/classes/, va ressembler à ceci :</p>
<pre>
<div class="codecolorer-container xml default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br /></div></td><td><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;?xml</span> <span style="color: #000066;">version</span>=<span style="color: #ff0000;">&quot;1.0&quot;</span> <span style="color: #000066;">encoding</span>=<span style="color: #ff0000;">&quot;UTF-8&quot;</span><span style="color: #000000; font-weight: bold;">?&gt;</span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;application</span></span><br />
<span style="color: #009900;"> &nbsp;<span style="color: #000066;">xmlns:xsi</span>=<span style="color: #ff0000;">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span><br />
<span style="color: #009900;"> &nbsp;<span style="color: #000066;">xmlns</span>=<span style="color: #ff0000;">&quot;http://www.zeroturnaround.com&quot;</span></span><br />
<span style="color: #009900;"> &nbsp;<span style="color: #000066;">xsi:schemaLocation</span>=<span style="color: #ff0000;">&quot;http://www.zeroturnaround.com http://www.zeroturnaround.com/alderaan/rebel-2_0.xsd&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;classpath<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;dir</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;D:\NetBeansProjects\WebApplication1\build\web\WEB-INF\classes&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/classpath<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/application<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></td></tr></tbody></table></div>
</pre>
<p>On demande donc de prendre à chaud tout ce qui va changer dans le répertoire où sont placées les classes compilées.</p>
<p>Dans les logs du démarrage de glassfish, on peut ainsi voir :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">INFO: JRebel: Directory 'D:\NetBeansProjects\WebApplication1\build\web\WEB-INF\classes' will be monitored for changes.</div></td></tr></tbody></table></div>
<p>Procédons à une modification mineure du corps de la méthode <code class="codecolorer java default"><span class="java">processRequest<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span></span></code> :</p>
<pre>
<div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br /></div></td><td><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #666666; font-style: italic;">// On a changé le message affiché</span><br />
out.<span style="color: #006633;">println</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Congratulations, the result is &quot;</span> <span style="color: #339933;">+</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span>result <span style="color: #339933;">==</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">?</span> <span style="color: #0000ff;">&quot;unpredictable&quot;</span> <span style="color: #339933;">:</span> result<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></td></tr></tbody></table></div>
</pre>
<p>Après compilation du fichier et rafraîchissement de la page dans le navigateur, on obtient immédiatement le changement :</p>
<div id="attachment_2435" class="wp-caption aligncenter" style="width: 655px"><a href="http://blog.excilys.com/wp-content/uploads/2010/07/hotswap.png"><img class="size-full wp-image-2435" title="hotswap" src="http://blog.excilys.com/wp-content/uploads/2010/07/hotswap.png" alt="" width="645" /></a><p class="wp-caption-text">Modification à chaud du corps d&#39;une méthode</p></div>
<p>Dans le cas présent, JRebel a fait l&#8217;équivalent du hotswapping standard de la JVM, mais sans avoir besoin d&#8217;être en mode debug.</p>
<h4>Un cran au-dessus : ajout de méthodes / classes</h4>
<p>Amusons-nous maintenant dans le domaine de l&#8217;inédit. Pour satisfaire notre envie de <a href="http://en.wikipedia.org/wiki/Separation_of_concerns"><em>separation of concerns</em></a>, on va externaliser le code métier dans une classe différente de la servlet :</p>
<pre>
<div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br /></div></td><td><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> Calc <span style="color: #009900;">&#123;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #003399;">Integer</span> add<span style="color: #009900;">&#40;</span><span style="color: #003399;">Integer</span> a, <span style="color: #003399;">Integer</span> b<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> a <span style="color: #339933;">+</span> b<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #003399;">Integer</span> substract<span style="color: #009900;">&#40;</span><span style="color: #003399;">Integer</span> a, <span style="color: #003399;">Integer</span> b<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> a <span style="color: #339933;">-</span> b <span style="color: #339933;">+</span> <span style="color: #cc66cc;">2</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #666666; font-style: italic;">// et dans la servlet :</span><br />
<span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>operation.<span style="color: #006633;">equals</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;add&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; result <span style="color: #339933;">=</span> Calc.<span style="color: #006633;">add</span><span style="color: #009900;">&#40;</span>a, b<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">else</span> <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>operation.<span style="color: #006633;">equals</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;sub&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; result <span style="color: #339933;">=</span> Calc.<span style="color: #006633;">substract</span><span style="color: #009900;">&#40;</span>a, b<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div>
</pre>
<p>On enregistre, on compile et on vérifie : la nouvelle classe (et indirectement de nouvelles méthodes) a été prise en compte automatiquement (pour en être sûr, on peut bidouiller l&#8217;addition pour qu&#8217;elle calcule a + b + 1 par exemple).</p>
<h4>Et les ressources ?</h4>
<p>Pour l&#8217;instant nous nous sommes contentés de modifier du code Java. Et si on essayait des fichiers properties ? Ca tombe bien, notre client vient justement de nous faire part de son vœu de pouvoir internationaliser le nom des opérations <em>add</em> et <em>sub</em> !</p>
<p>On va donc utiliser un <a href="http://download.oracle.com/docs/cd/E17476_01/javase/1.5.0/docs/api/java/util/PropertyResourceBundle.html">ResourceBundle</a> :</p>
<pre>
<div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br /></div></td><td><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>operation.<span style="color: #006633;">equals</span><span style="color: #009900;">&#40;</span><span style="color: #003399;">ResourceBundle</span>.<span style="color: #006633;">getBundle</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;operations&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">getString</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;add&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; result <span style="color: #339933;">=</span> Calc.<span style="color: #006633;">add</span><span style="color: #009900;">&#40;</span>a, b<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">else</span> <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>operation.<span style="color: #006633;">equals</span><span style="color: #009900;">&#40;</span><span style="color: #003399;">ResourceBundle</span>.<span style="color: #006633;">getBundle</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;operations&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">getString</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;sub&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; result <span style="color: #339933;">=</span> Calc.<span style="color: #006633;">substract</span><span style="color: #009900;">&#40;</span>a, b<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div>
</pre>
<div class="codecolorer-container properties default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="properties codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #808080; font-style: italic;"># operations.properties</span><br />
<span style="color: #000080; font-weight:bold;">add</span> <span style="color: #000000;">=</span><span style="color: #008000; font-weight:bold;"> add</span><br />
<span style="color: #000080; font-weight:bold;">sub</span> <span style="color: #000000;">=</span><span style="color: #008000; font-weight:bold;"> sub</span></div></td></tr></tbody></table></div>
<p>On compile, on rafraîchit et là&#8230; c&#8217;est le drame !</p>
<pre>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">WARNING: StandardWrapperValve[Calculator]: PWC1406: Servlet.service() for servlet Calculator threw exception<br />
java.util.MissingResourceException: Can't find bundle for base name operations, locale en_GB<br />
&nbsp; &nbsp; &nbsp; &nbsp; at java.util.ResourceBundle.throwMissingResourceException(ResourceBundle.java:1521)<br />
&nbsp; &nbsp; &nbsp; &nbsp; at java.util.ResourceBundle.getBundleImpl(ResourceBundle.java:1260)<br />
&nbsp; &nbsp; &nbsp; &nbsp; at java.util.ResourceBundle.getBundle(ResourceBundle.java:715)<br />
&nbsp; &nbsp; &nbsp; &nbsp; at com.excilys.blog.jrebel.servlet.Calculator$$M$6334694c.processRequest(Calculator.java:38)<br />
&nbsp; &nbsp; &nbsp; &nbsp; at com.excilys.blog.jrebel.servlet.Calculator$$A$6334694c.processRequest()&lt;generated&gt;<br />
&nbsp; &nbsp; &nbsp; &nbsp; at com.excilys.blog.jrebel.servlet.Calculator.processRequest(Calculator.java:51)<br />
&nbsp; &nbsp; &nbsp; &nbsp; at com.excilys.blog.jrebel.servlet.Calculator$$M$6334694c.doGet(Calculator.java:65)<br />
&nbsp; &nbsp; &nbsp; &nbsp; at com.excilys.blog.jrebel.servlet.Calculator$$A$6334694c.doGet()&lt;generated&gt;<br />
&nbsp; &nbsp; &nbsp; &nbsp; at com.excilys.blog.jrebel.servlet.Calculator.doGet(Calculator.java:65)</div></td></tr></tbody></table></div>
</pre>
<p>Et oui, les ressources sont cherchées dans le répertoire <code class="codecolorer text default"><span class="text">build\web\WEB-INF\classes\operations.properties</span></code>, hors comme on ne fait pas de build complet le fichier properties qu&#8217;on vient de créer ne s&#8217;y trouve pas encore <img src='http://blog.excilys.com/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> . Pas de souci, on le copie à la main (ou on fait un build complet, mais c&#8217;est plus long), et là ça marche ! Remarquez au passage que les classes mentionnées dans la stacktrace ont des noms un peu bizarres, certaines sont marquées <code class="codecolorer text default"><span class="text">&lt;generated&gt;</span></code> : cela correspond à ce que j&#8217;ai expliqué plus haut au sujet du fonctionnement interne de JRebel.</p>
<p>Zut, le client vient de décider qu&#8217;à présent, on aura des noms d&#8217;opérations en français. Pas de souci, on a juste à changer notre properties (celui dans le dossier <code class="codecolorer text default"><span class="text">build/</span></code>, sauf si vous décidez de monitorer également la version dans <code class="codecolorer text default"><span class="text">src/</span></code>), et les changements sont pris à chaud :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">INFO: JRebel: Reloading class 'com.excilys.blog.jrebel.servlet.Calculator'.<br />
INFO: JRebel: Reloaded bundle file:/D:/NetBeansProjects/WebApplication1/build/web/WEB-INF/classes/operations.properties</div></td></tr></tbody></table></div>
<h4>Encore une <em>killer-feature</em> : le plugin Spring</h4>
<p>Comme évoqué dans les principes de fonctionnement, JRebel supporte entre autres les changements à chaud de configuration du framework Spring grâce à un plugin dédié. Voyons un peu comment ça fonctionne. Après avoir supprimé le <code class="codecolorer java default"><span class="java"><span style="color: #000000; font-weight: bold;">static</span></span></code> des méthodes de la classe <code class="codecolorer java default"><span class="java">Calc</span></code>, j&#8217;ai décidé d&#8217;en faire un bean Spring :</p>
<pre>
<div class="codecolorer-container xml default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br /></div></td><td><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;?xml</span> <span style="color: #000066;">version</span>=<span style="color: #ff0000;">&quot;1.0&quot;</span> <span style="color: #000066;">encoding</span>=<span style="color: #ff0000;">&quot;UTF-8&quot;</span><span style="color: #000000; font-weight: bold;">?&gt;</span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;beans</span> <span style="color: #000066;">xmlns</span>=<span style="color: #ff0000;">&quot;http://www.springframework.org/schema/beans&quot;</span></span><br />
<span style="color: #009900;"> &nbsp; &nbsp; &nbsp; <span style="color: #000066;">xmlns:xsi</span>=<span style="color: #ff0000;">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span><br />
<br />
<span style="color: #009900;"> &nbsp; &nbsp; &nbsp; <span style="color: #000066;">xsi:schemaLocation</span>=<span style="color: #ff0000;">&quot;http://www.springframework.org/schema/beans</span><br />
<span style="color: #009900;"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; http://www.springframework.org/schema/beans/spring-beans-3.0.xsd&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
<br />
&nbsp; &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;calc&quot;</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;com.excilys.blog.jrebel.Calc&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
<br />
&nbsp; &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;org.springframework.web.context.support.ServletContextAttributeExporter&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;property</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;attributes&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;map<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;entry</span> <span style="color: #000066;">key</span>=<span style="color: #ff0000;">&quot;calcBean&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <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;calc&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/entry<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/map<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/property<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/bean<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/beans<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></td></tr></tbody></table></div>
</pre>
<p>Ce bean est ensuite <a href="http://andykayley.blogspot.com/2007/11/how-to-inject-spring-beans-into.html">récupéré dans la servlet</a> de la manière suivante :</p>
<div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">Calc calc <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>Calc<span style="color: #009900;">&#41;</span>getServletContext<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">getAttribute</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;calcBean&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #666666; font-style: italic;">//...</span><br />
result <span style="color: #339933;">=</span> calc.<span style="color: #006633;">add</span><span style="color: #009900;">&#40;</span>a, b<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></td></tr></tbody></table></div>
<p>Je vous passe la configuration du <code class="codecolorer text default"><span class="text">web.xml</span></code>, elle est tout à fait standard. Cependant JRebel ne permet pas de prendre à chaud les changements dans <code class="codecolorer text default"><span class="text">web.xml</span></code>, on va donc être obligés de redéployer notre application (mais on le fera plus après, promis <img src='http://blog.excilys.com/wp-includes/images/smilies/icon_biggrin.gif' alt=':-D' class='wp-smiley' /> ). Redéploiement et rafraîchissement de la page web, ouf, tout fonctionne normalement.</p>
<p>Pour tester le plugin Spring, on va introduire une modification mineure : renommer l&#8217;attribut du contexte permettant de récupérer bean.</p>
<div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br /></div></td><td><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #666666; font-style: italic;">// dans applicationContext.xml, on change la balise &lt;entry&gt; en</span><br />
<span style="color: #666666; font-style: italic;">// &nbsp; &lt;entry key=&quot;myCalcBean&quot;&gt;</span><br />
<span style="color: #666666; font-style: italic;">// et dans le code Java, on a donc :</span><br />
Calc calc <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>Calc<span style="color: #009900;">&#41;</span>getServletContext<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">getAttribute</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;myCalcBean&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></td></tr></tbody></table></div>
<p>Compilation, rafraîchissement (en ces temps de fortes chaleurs&#8230;), applaudissements. On vient de bénéficier d&#8217;une modification de la configuration de Spring sans avoir à redéployer !</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">INFO: JRebel: Reloading class 'com.excilys.blog.jrebel.servlet.Calculator'.<br />
INFO: JRebel-Spring: Reloading Spring bean definitions in 'file:/D:/NetBeansProjects/WebApplication1/build/web/WEB-INF/classes/applicationContext.xml'.<br />
INFO: Loading XML bean definitions from file [D:\NetBeansProjects\WebApplication1\build\web\WEB-INF\classes\applicationContext.xml]<br />
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@4cea16: defining beans [org.springframework.web.context.support.ServletContextAttributeExporter#0,calc,org.springframework.web.context.support.ServletContextAttributeExporter#1]; root of factory hierarchy<br />
INFO: Exported ServletContext attribute with name 'myCalcBean'</div></td></tr></tbody></table></div>
<h3>Conclusion</h3>
<p>Résumons un peu. Avec un seul déploiement (parce que je m&#8217;y suis pris trop tard, avouons-le), on a réussi à prendre en compte immédiatement des modifications de méthodes, des ajouts des classes, des modifications des fichiers properties accédés par un ResourceBundle et surtout des fichiers de configuration de framework (Spring dans cet exemple). Ça en jette, non ? Tout ça pour pas un rond si vos développement durent moins de 30 jours, sinon il faudra débourser une <a href="http://sales.zeroturnaround.com/">somme relativement modeste</a> (189$ pour une licence annuelle standard).</p>
<p><div id="attachment_2495" class="wp-caption alignright" style="width: 210px"><a href="http://blog.excilys.com/wp-content/uploads/2010/08/lerebelle2.jpg"><img src="http://blog.excilys.com/wp-content/uploads/2010/08/lerebelle2.jpg" alt="" title="Le Rebelle" width="200" height="274" class="size-full wp-image-2495" /></a><p class="wp-caption-text">Le Rebelle aussi utilise JRebel.</p></div><br />
Sachez que je n&#8217;ai couvert qu&#8217;une petite partie de tout ce que JRebel sait faire, histoire de garder un article d&#8217;une taille raisonnable. Je vous laisse le soin d&#8217;explorer et de tester à fond cette petite merveille pour développeurs !</p>
<p>Petit plus pour les décideurs, à chaque démarrage du serveur, JRebel affiche des estimations sur le précieux temps qu&#8217;il vous a fait gagner, de manière à mesurer les gains qu&#8217;apportent de tels outils :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">Over the last 3 days JRebel prevented<br />
at least 18 redeploys/restarts saving you about 0.7 hours.</div></td></tr></tbody></table></div>
<h3>Pour aller plus loin</h3>
<ul>
<li><a href="http://www.zeroturnaround.com/jrebel/">Site de JRebel</a></li>
<li><a href="http://jetoile.blogspot.com/2010/02/jrebel-ou-comment-accelerer-le_24.html">JRebel ou comment accélérer le développement</a></li>
<li><a href="http://javaposse.com/java_posse_306_j_rebel_interview">Java Posse #306 &#8211; JRebel Interview</a></li>
<li><a href="http://www.zeroturnaround.com/jrebel/configuration/maven/">Youpi ! Ca marche aussi avec Maven</a></li>
<li><a href="http://www.zeroturnaround.com/scala-license/">Enfin une bonne raison de se mettre à Scala</a> <img src='http://blog.excilys.com/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </li>
</ul>
<img src="http://feeds.feedburner.com/~r/blogexcilyscom/~4/aSDOZsFqkys" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.excilys.com/2010/07/15/oubliez-les-redeploiements-grace-a-jrebel/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://blog.excilys.com/2010/07/15/oubliez-les-redeploiements-grace-a-jrebel/</feedburner:origLink></item>
		<item>
		<title>Illuminez vos logs dans Eclipse</title>
		<link>http://feedproxy.google.com/~r/blogexcilyscom/~3/y0heob9aTfU/</link>
		<comments>http://blog.excilys.com/2010/06/30/illuminez-vos-logs-dans-eclipse/#comments</comments>
		<pubDate>Wed, 30 Jun 2010 08:30:15 +0000</pubDate>
		<dc:creator>Bastien JANSEN</dc:creator>
				<category><![CDATA[Non classé]]></category>
		<category><![CDATA[coloration]]></category>
		<category><![CDATA[eclipse]]></category>
		<category><![CDATA[logs]]></category>
		<category><![CDATA[outils]]></category>
		<category><![CDATA[performances]]></category>

		<guid isPermaLink="false">http://blog.excilys.com/?p=2405</guid>
		<description><![CDATA[Introduction
Comme beaucoup de lecteurs de ce blog, j&#8217;utilise un IDE au quotidien. Sur mon projet actuel, c&#8217;est Eclipse combiné à un serveur Websphere. Pour des raisons pratiques, je fais un tail -f des logs du serveur dans la console d&#8217;Eclipse, et qui dit serveur d&#8217;applications Java + logs en niveau DEBUG dit énormément d&#8217;informations à [...]]]></description>
			<content:encoded><![CDATA[<h3>Introduction</h3>
<p>Comme beaucoup de lecteurs de ce blog, j&#8217;utilise un IDE au quotidien. Sur mon projet actuel, c&#8217;est Eclipse combiné à un serveur Websphere. Pour des raisons pratiques, je fais un <code class="codecolorer text default"><span class="text">tail -f</span></code> des logs du serveur dans la console d&#8217;Eclipse, et qui dit serveur d&#8217;applications Java + logs en niveau <code class="codecolorer text default"><span class="text">DEBUG</span></code> dit énormément d&#8217;informations à scanner pour trouver ce qui m&#8217;intéresse réellement (quelques Mo de logs par jour !).</p>
<h3>Colore tes logs !</h3>
<p>La solution que j&#8217;ai retenue pour facilement m&#8217;y retrouver, c&#8217;est <a href="http://marian.musgit.com/projects_grepconsole.php">Grep Console</a>. Ce plugin pour Eclipse permet de colorier dans une console certaines parties de texte qui matchent une ou plusieurs expressions régulières. Par exemple, les <code class="codecolorer text default"><span class="text">WARN</span></code> en orange et les <code class="codecolorer text default"><span class="text">ERROR</span></code> en blanc sur fond rouge.</p>
<div id="attachment_2408" class="wp-caption aligncenter" style="width: 615px"><a href="http://blog.excilys.com/wp-content/uploads/2010/08/screenshot.png"><img class="size-full wp-image-2408 " title="Configuration de Grep Console" src="http://blog.excilys.com/wp-content/uploads/2010/08/screenshot.png" alt="Configuration de Grep Console" width="605" height="386" /></a><p class="wp-caption-text">Les boites de dialogues ultra-simples de configuration de Grep Console</p></div>
<p>On voit dans la fenêtre de gauche toutes les expressions régulières que j&#8217;ai choisies de matcher et dans celle de droite la configuration de l&#8217;une d&#8217;entre elles : définition de la regexp, choix des couleurs d&#8217;arrière-plan ou d&#8217;avant-plan pour la ligne entière ou pour les <em>groupes</em> capturés par des parenthèses (cependant on ne peut pas imbriquer les parenthèses).</p>
<p>Voici le résultat dans la console d&#8217;Eclipse :</p>
<p style="text-align: center;"><a href="http://blog.excilys.com/wp-content/uploads/2010/08/screenshot2.png"><img class="aligncenter size-full wp-image-2410" title="Aperçu de la coloration des logs" src="http://blog.excilys.com/wp-content/uploads/2010/08/screenshot2.png" alt="Aperçu de la coloration des logs" width="880" height="302" /></a></p>
<h3>Conclusion</h3>
<p>Simple mais efficace, je vous conseille vivement d&#8217;installer ce plugin qui permet de gagner du temps si vous avez des logs sous les yeux à longueur de journée ! Rendez-vous sur l&#8217;<em>update site </em><a href="http://eclipse.musgit.com">http://eclipse.musgit.com</a>. Seul bémol, je n&#8217;ai pas encore trouvé d&#8217;astuce pour colorier d&#8217;anciens logs dans d&#8217;autres fichiers (une sorte de <code class="codecolorer text default"><span class="text">less</span></code> coloré). Si vous avez un outil qui fait ce genre de choses, je suis preneur <img src='http://blog.excilys.com/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> .</p>
<p style="text-align: center;">
<img src="http://feeds.feedburner.com/~r/blogexcilyscom/~4/y0heob9aTfU" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.excilys.com/2010/06/30/illuminez-vos-logs-dans-eclipse/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://blog.excilys.com/2010/06/30/illuminez-vos-logs-dans-eclipse/</feedburner:origLink></item>
		<item>
		<title>Dé-switcher n’est pas jouer</title>
		<link>http://feedproxy.google.com/~r/blogexcilyscom/~3/aw_n_vwndYM/</link>
		<comments>http://blog.excilys.com/2010/06/25/de-switcher-nest-pas-jouer/#comments</comments>
		<pubDate>Thu, 24 Jun 2010 22:20:38 +0000</pubDate>
		<dc:creator>Pierre-Yves RICAU</dc:creator>
				<category><![CDATA[Non classé]]></category>
		<category><![CDATA[bonnes pratiques]]></category>
		<category><![CDATA[clean-code]]></category>
		<category><![CDATA[code propre]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[refactoring]]></category>
		<category><![CDATA[switch]]></category>

		<guid isPermaLink="false">http://blog.excilys.com/?p=2375</guid>
		<description><![CDATA[Amis utilisateurs de Checkstyle, avez-vous remarqué que les switch sont des sources inépuisables de complexité cyclomatique ? Sans parler de leur équivalent pour les objets, les if &#40;&#41; &#123;&#125; else if &#40;&#41;&#123;&#125; else if &#40;&#41;&#123;&#125; else if &#40;&#41;&#123;&#125; à répétition.
Parmi les reproches récurrents faits aux switch, il y a le fait qu&#8217;ils ne respectent pas [...]]]></description>
			<content:encoded><![CDATA[<p>Amis utilisateurs de <a href="http://checkstyle.sourceforge.net/">Checkstyle</a>, avez-vous remarqué que les <a href="http://java.sun.com/docs/books/tutorial/java/nutsandbolts/switch.html">switch</a> sont des sources inépuisables de <a href="http://fr.wikipedia.org/wiki/Nombre_cyclomatique">complexité cyclomatique</a> ? Sans parler de leur équivalent pour les objets, les <code class="codecolorer java default"><span class="java"><span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">else</span> <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">else</span> <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">else</span> <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><span style="color: #009900;">&#125;</span></span></code> à répétition.</p>
<p>Parmi les reproches récurrents faits aux <code class="codecolorer java default"><span class="java"><span style="color: #000000; font-weight: bold;">switch</span></span></code>, il y a le fait qu&#8217;ils ne respectent pas le principe <a href="http://fr.wikipedia.org/wiki/Principe_ouvert/ferm%C3%A9">Ouvert/Fermé</a>. A chaque ajout de nouvelles valeurs, il faut modifier tous les <code class="codecolorer java default"><span class="java"><span style="color: #000000; font-weight: bold;">switch</span></span></code> qui les manipulent.</p>
<p><span id="more-2375"></span><br />
Il est toujours possible de se passer d&#8217;un switch. Un moyen simple est d&#8217;utiliser une <a href="http://java.sun.com/javase/6/docs/api/java/util/Map.html">Map</a>. Ainsi, le code suivant :</p>
<pre>
<div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br /></div></td><td><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #003399;">String</span> getMessage<span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">int</span> messageCode<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #003399;">String</span> message<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">switch</span> <span style="color: #009900;">&#40;</span>messageCode<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">case</span> <span style="color: #cc66cc;">42</span><span style="color: #339933;">:</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; message <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;the Answer to the Ultimate Question of Life, the Universe, and Everything.&quot;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">break</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">case</span> <span style="color: #cc66cc;">13</span><span style="color: #339933;">:</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; message <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;Good luck!&quot;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">break</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// [...]</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">default</span><span style="color: #339933;">:</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">throw</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">IllegalArgumentException</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Unknown code&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> message<span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div>
</pre>
<p>devient :</p>
<pre>
<div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br /></div></td><td><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">final</span> Map<span style="color: #339933;">&lt;</span>Integer, String<span style="color: #339933;">&gt;</span> &nbsp;messagesByCode <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> HashMap<span style="color: #339933;">&lt;</span>Integer, String<span style="color: #339933;">&gt;</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000066; font-weight: bold;">void</span> initMessagesByCode<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; messagesByCode.<span style="color: #006633;">put</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">42</span>, <span style="color: #0000ff;">&quot;the Answer to the Ultimate Question of Life, the Universe, and Everything.&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; messagesByCode.<span style="color: #006633;">put</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">13</span>, <span style="color: #0000ff;">&quot;Good luck!&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// [...]</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #003399;">String</span> getMessage<span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">int</span> messageCode<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #003399;">String</span> message <span style="color: #339933;">=</span> messagesByCode.<span style="color: #006633;">get</span><span style="color: #009900;">&#40;</span>messageCode<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>message <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><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">throw</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">IllegalArgumentException</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Unknown code&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> message<span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div>
</pre>
<p>Cela fonctionne aussi si le <code class="codecolorer java default"><span class="java"><span style="color: #000000; font-weight: bold;">switch</span></span></code> (ou les if/else) contient du code à exécuter qui varie suivant les cas. Ainsi :</p>
<pre>
<div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br /></div></td><td><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> doAction<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> action<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;syso&quot;</span>.<span style="color: #006633;">equals</span><span style="color: #009900;">&#40;</span>action<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003399;">System</span>.<span style="color: #006633;">out</span>.<span style="color: #006633;">println</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Yeah&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">else</span> <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;syserr&quot;</span>.<span style="color: #006633;">equals</span><span style="color: #009900;">&#40;</span>action<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003399;">System</span>.<span style="color: #006633;">err</span>.<span style="color: #006633;">println</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Yahoo&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span> <span style="color: #666666; font-style: italic;">// [...]</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">else</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">throw</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">IllegalArgumentException</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Unknown action&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span><br />
<span style="color: #666666; font-style: italic;">// [...]</span><br />
doAction<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;syso&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></td></tr></tbody></table></div>
</pre>
<p>devient (j&#8217;en conviens, des <a href="http://en.wikipedia.org/wiki/First-class_function">first-class functions</a> simplifieraient le code) :</p>
<pre>
<div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br /></div></td><td><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">final</span> Map<span style="color: #339933;">&lt;</span>String, Runnable<span style="color: #339933;">&gt;</span> actionsByName <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> HashMap<span style="color: #339933;">&lt;</span>String, Runnable<span style="color: #339933;">&gt;</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000066; font-weight: bold;">void</span> initActionsByName<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; actionsByName.<span style="color: #006633;">put</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;syso&quot;</span>, <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">Runnable</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> run<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003399;">System</span>.<span style="color: #006633;">out</span>.<span style="color: #006633;">println</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Yeah&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; actionsByName.<span style="color: #006633;">put</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;syserr&quot;</span>, <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">Runnable</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> run<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003399;">System</span>.<span style="color: #006633;">err</span>.<span style="color: #006633;">println</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Yahoo&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> doAction<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> action<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #003399;">Runnable</span> runnable <span style="color: #339933;">=</span> actionsByName.<span style="color: #006633;">get</span><span style="color: #009900;">&#40;</span>action<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>runnable <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><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">throw</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">IllegalArgumentException</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Unknown action&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; runnable.<span style="color: #006633;">run</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
<span style="color: #666666; font-style: italic;">// [...]</span><br />
doAction<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;syso&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></td></tr></tbody></table></div>
</pre>
<p>Clairement, si ce type de modification permet de se passer de <code class="codecolorer java default"><span class="java"><span style="color: #000000; font-weight: bold;">switch</span></span></code> sans modifier la signature des méthodes, elle n&#8217;est pas idéale. Une bien meilleure option ici serait de se souvenir que Java est un langage <a href="http://java.sun.com/docs/books/tutorial/java/concepts/object.html">orienté Objet</a>, et utiliser le polymorphisme pour implémenter le <a href="http://en.wikipedia.org/wiki/Strategy_pattern">pattern strategy</a> <img src='http://blog.excilys.com/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' />  :</p>
<pre>
<div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br /></div></td><td><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">interface</span> <span style="color: #003399;">Action</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">void</span> doAction<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
<span style="color: #666666; font-style: italic;">// [...]</span><br />
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> doAction<span style="color: #009900;">&#40;</span><span style="color: #003399;">Action</span> action<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; action.<span style="color: #006633;">doAction</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
<span style="color: #666666; font-style: italic;">// [...]</span><br />
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> Syso <span style="color: #000000; font-weight: bold;">implements</span> <span style="color: #003399;">Action</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> doAction<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003399;">System</span>.<span style="color: #006633;">out</span>.<span style="color: #006633;">println</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Yeah&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span><br />
<span style="color: #666666; font-style: italic;">// [...]</span><br />
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> Syserr <span style="color: #000000; font-weight: bold;">implements</span> <span style="color: #003399;">Action</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> doAction<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003399;">System</span>.<span style="color: #006633;">err</span>.<span style="color: #006633;">println</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Yahoo&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span><br />
<span style="color: #666666; font-style: italic;">// [...]</span><br />
doAction<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> Syso<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></td></tr></tbody></table></div>
</pre>
<p>On pourrait enfin utiliser les possibilités offertes par les <a href="http://weblogs.java.net/blog/2005/01/31/implementing-state-design-pattern-using-enums">enum Java</a> :</p>
<pre>
<div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br /></div></td><td><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">enum</span> ActionEnum <span style="color: #000000; font-weight: bold;">implements</span> <span style="color: #003399;">Action</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; SYSO <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> doAction<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003399;">System</span>.<span style="color: #006633;">out</span>.<span style="color: #006633;">println</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Yeah&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span>,<br />
&nbsp; &nbsp; SYSERR <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> doAction<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003399;">System</span>.<span style="color: #006633;">err</span>.<span style="color: #006633;">println</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Yahoo&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
<span style="color: #666666; font-style: italic;">// [...]</span><br />
doAction<span style="color: #009900;">&#40;</span>ActionEnum.<span style="color: #006633;">SYSO</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></td></tr></tbody></table></div>
</pre>
<p>J&#8217;espère que ce court article vous aura convaincu qu&#8217;il est tout à fait possible de se passer des <code class="codecolorer java default"><span class="java"><span style="color: #000000; font-weight: bold;">switch</span></span></code>. Un code comprenant des <code class="codecolorer java default"><span class="java"><span style="color: #000000; font-weight: bold;">switch</span></span></code> et autres <code class="codecolorer java default"><span class="java"><span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">else</span> <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><span style="color: #009900;">&#125;</span></span></code> est en général tout sauf simple et maintenable.<br />
Dans <a href="http://www.amazon.fr/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882/">Clean Code</a>, <a href="http://www.objectmentor.com/omTeam/martin_r.html">Uncle Bob Martin</a> conseille d&#8217;ailleurs d&#8217;encapsuler le code lié aux <code class="codecolorer java default"><span class="java"><span style="color: #000000; font-weight: bold;">switch</span></span></code> dans des <a href="http://fr.wikipedia.org/wiki/Fabrique_abstraite_%28patron_de_conception%29">fabriques abstraites</a>, afin de ne pas les laisser polluer le reste du code.</p>
<img src="http://feeds.feedburner.com/~r/blogexcilyscom/~4/aw_n_vwndYM" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.excilys.com/2010/06/25/de-switcher-nest-pas-jouer/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		<feedburner:origLink>http://blog.excilys.com/2010/06/25/de-switcher-nest-pas-jouer/</feedburner:origLink></item>
		<item>
		<title>De l’audit avec hibernate</title>
		<link>http://feedproxy.google.com/~r/blogexcilyscom/~3/M3CCpUE0jYk/</link>
		<comments>http://blog.excilys.com/2010/06/16/de-laudit-avec-hibernate/#comments</comments>
		<pubDate>Wed, 16 Jun 2010 14:10:06 +0000</pubDate>
		<dc:creator>Laurent STEMMER</dc:creator>
				<category><![CDATA[Non classé]]></category>
		<category><![CDATA[audit]]></category>
		<category><![CDATA[back-dynamite]]></category>
		<category><![CDATA[hibernate]]></category>
		<category><![CDATA[java]]></category>

		<guid isPermaLink="false">http://blog.excilys.com/?p=2159</guid>
		<description><![CDATA[Nous allons parler de l’interface Interceptor et de son utilisation dans le but d’auditer du code.]]></description>
			<content:encoded><![CDATA[<p>Hello my dear students*,</p>
<blockquote><p>Pouvez-vous me faire un rapport sur tous les ajouts et les modifications qui ont été faits sur la table des factures en production depuis 5 ans ? </p></blockquote>
<p>Hibernate a vraiment pensé à tout, aujourd’hui nous allons parler de l’interface Interceptor et de son utilisation dans le but de faciliter <a href="http://en.wikipedia.org/wiki/Information_technology_audit">l&#8217;audit du système d&#8217;information</a> (ici la base de données).</p>
<div><span id="more-2159"></span></div>
<h3>L&#8217;interceptor hibernate</h3>
<p>Cette interface fournit des méthodes qui interceptent différents événements de la session comme la suppression, l&#8217;ajout ou la modification de données.</p>
<p>Vous pouvez implémenter <a href="http://docs.jboss.org/hibernate/stable/core/api/org/hibernate/Interceptor.html">Interceptor </a>directement, ou mieux : étendre <a href="http://docs.jboss.org/hibernate/stable/core/api/org/hibernate/EmptyInterceptor.html">EmptyInterceptor </a>et n&#8217;en surcharger que les méthodes qui vous intéressent. Voici un exemple :</p>
<div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;height:300px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br /></div></td><td><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #008000; font-style: italic; font-weight: bold;">/**<br />
&nbsp;* Audite l'insertion et la mise à jour des entités implémentant l'interface {@link ExcilysAuditable}.<br />
&nbsp;* &lt;p&gt;<br />
&nbsp;*<br />
&nbsp;* Le choix de la méthode d'audit est laissé à la discretion du codeur.<br />
&nbsp;*<br />
&nbsp;*/</span><br />
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> ExcilysAuditLogInterceptor <span style="color: #000000; font-weight: bold;">extends</span> EmptyInterceptor <span style="color: #009900;">&#123;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">boolean</span> onSave<span style="color: #009900;">&#40;</span><span style="color: #003399;">Object</span> entity,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #003399;">Serializable</span> id,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #003399;">Object</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> state,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #003399;">String</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> propertyNames,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Type<span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> types<span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">throws</span> CallbackException <span style="color: #009900;">&#123;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>entity <span style="color: #000000; font-weight: bold;">instanceof</span> ExcilysAuditable<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// loguez de la manière qui vous plaira que l'entité à été insérée</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">false</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// parce que l'on a pas modifié l'entité impliquée dans le callback</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">boolean</span> onFlushDirty<span style="color: #009900;">&#40;</span><span style="color: #003399;">Object</span> entity,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003399;">Serializable</span> id,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003399;">Object</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> currentState,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003399;">Object</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> previousState,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003399;">String</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> propertyNames,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Type<span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> types<span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">throws</span> CallbackException <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>entity <span style="color: #000000; font-weight: bold;">instanceof</span> ExcilysAuditable<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// loguez de la manière qui vous plaira que l'entité à été modifiée</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">false</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// parce que l'on a pas modifié l'entité impliquée dans le callback</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div>
<p>Attention cependant, auditer les insertions et les mises à jour peut ralentir votre application !</p>
<p>Pour rendre effective l&#8217;utilisation par Hibernate de votre Interceptor, passez-le en paramètre lors de la  création de la session (sf correspond à la SessionFactory) :</p>
<div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">Session session <span style="color: #339933;">=</span> sf.<span style="color: #006633;">openSession</span><span style="color: #009900;">&#40;</span> <span style="color: #000000; font-weight: bold;">new</span> ExcilysAuditLogInterceptor<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></td></tr></tbody></table></div>
<h3>Interceptors versus Triggers</h3>
<p>Pour se rappeler de ce qu&#8217;est un Trigger SGBD, lire <a href="http://sqlpro.developpez.com/cours/sqlaz/techniques/#L3">cet article</a> !</p>
<p>Les triggers</p>
<div>
<ul>
<li>sont rapides</li>
<li>seront aussi appelés si vous faites des insert en base directement (on est donc sûr d&#8217;auditer tout changement)</li>
</ul>
</div>
<p>Les Interceptors</p>
<div>
<ul>
<li>ne dépendent pas du type de base de données (par exemple <a href="http://access.developpez.com/faq/?page=General#Triggers">Access ne gère pas les triggers</a>)</li>
<li>permettent de récupérer des données système comme la locale ou l&#8217;utilisateur de la session</li>
</ul>
</div>
<h3>Conclusion</h3>
<p>Voilà, encore une façon supplémentaire de tracer ce que font vos utilisateurs. N&#8217;oubliez pas que les erreurs sont plus faciles à mettre sur le dos d&#8217;un autre quand <a href="http://fr.wikipedia.org/wiki/Pr%C3%A9somption_d'innocence">il existe des preuves</a> qui vont dans votre sens <img src='http://blog.excilys.com/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> .</p>
<blockquote><p>Pouvez-vous me faire un rapport sur tous les ajouts et les modifications qui ont été faits sur la table des factures en production depuis 5 ans ? </p></blockquote>
<blockquote><p>Mais bien sûr je n&#8217;ai qu&#8217;à faire <strong>haut haut bas bas gauche droite gauche droite b a</strong>, et le tour est joué ! Et en plus, je vous ai fait un café !</p></blockquote>
<blockquote><p>Bravo, j&#8217;ai pu démasquer des centaines de fraudes grâce à vous ! Vous êtes trop puissant Black Dynamite !</p></blockquote>
<div id="attachment_2232" class="wp-caption aligncenter" style="width: 212px"><a href="http://blog.excilys.com/wp-content/uploads/2010/06/black_dynamite_ver3.jpg"><img src="http://blog.excilys.com/wp-content/uploads/2010/06/black_dynamite_ver3-202x300.jpg" alt="" width="202" height="300" class="size-medium wp-image-2232" /></a><p class="wp-caption-text">Cuz there aint no hope for dudes who deal dope!</p></div>
<p>* référence à <a href="http://en.wikipedia.org/wiki/Marina_Orlova">Marina Orlova</a>, qui m&#8217;a appris que l&#8217;etymologie pouvait être sexy.</p>
<img src="http://feeds.feedburner.com/~r/blogexcilyscom/~4/M3CCpUE0jYk" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.excilys.com/2010/06/16/de-laudit-avec-hibernate/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		<feedburner:origLink>http://blog.excilys.com/2010/06/16/de-laudit-avec-hibernate/</feedburner:origLink></item>
		<item>
		<title>Un peu de LOLcode…</title>
		<link>http://feedproxy.google.com/~r/blogexcilyscom/~3/4dQl3q60IJw/</link>
		<comments>http://blog.excilys.com/2010/06/14/un-peu-de-lolcode/#comments</comments>
		<pubDate>Mon, 14 Jun 2010 16:05:34 +0000</pubDate>
		<dc:creator>Bastien JANSEN</dc:creator>
				<category><![CDATA[Non classé]]></category>
		<category><![CDATA[entreprise]]></category>
		<category><![CDATA[fun]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[lol]]></category>

		<guid isPermaLink="false">http://blog.excilys.com/?p=1997</guid>
		<description><![CDATA[Introduction
Dans cet article, je vous propose quelque chose d&#8217;assez différent des sujets abordés habituellement. En lisant du code écrit par d&#8217;autres développeurs, je suis resté perplexe sur quelques méthodes. Après les avoir relues quelques fois, la façon d&#8217;écrire m&#8217;a fait sourire, comme quoi d&#8217;un développeur à l&#8217;autre les méthodes de réflexion et d&#8217;écriture de code [...]]]></description>
			<content:encoded><![CDATA[<h4>Introduction</h4>
<p>Dans cet article, je vous propose quelque chose d&#8217;assez différent des sujets abordés habituellement. En lisant du code écrit par d&#8217;autres développeurs, je suis resté perplexe sur quelques méthodes. Après les avoir relues quelques fois, la façon d&#8217;écrire m&#8217;a fait sourire, comme quoi d&#8217;un développeur à l&#8217;autre les méthodes de réflexion et d&#8217;écriture de code varient fortement.</p>
<p>Je vous propose donc quelques extraits de code méritant le détour, ça donne des snippets assez drôles, cherchez l&#8217;erreur !<br />
<span id="more-1997"></span></p>
<h4>Continue comme ça</h4>
<pre>
<div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br /></div></td><td><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #003399;">Object</span> i <span style="color: #339933;">:</span> list<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>condition<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; doSomeStuff<span style="color: #009900;">&#40;</span>someArguments<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">continue</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; doSomeStuff<span style="color: #009900;">&#40;</span>someOtherArguments<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div>
</pre>
<p><code class="codecolorer java default"><span class="java"><span style="color: #000000; font-weight: bold;">continue</span></span></code>, what <code class="codecolorer java default"><span class="java"><span style="color: #000000; font-weight: bold;">else</span></span></code>? <em>(ce jeu de mots est © <a href="http://blog.excilys.com/author/pyricau/">Pierre-Yves Ricau</a>)</em></p>
<h4>Tu peux pas test</h4>
<p>Contexte : imaginez une méthode <code class="codecolorer java default"><span class="java">initialize<span style="color: #009900;">&#40;</span>java.<span style="color: #006633;">util</span>.<span style="color: #003399;">Properties</span><span style="color: #009900;">&#41;</span></span></code> qui s&#8217;attend à la présence d&#8217;une propriété <code class="codecolorer java default"><span class="java">MY_PROPERTY</span></code> pour l&#8217;utiliser lors de l&#8217;initialisation d&#8217;un objet :</p>
<pre>
<div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br /></div></td><td><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> initialize<span style="color: #009900;">&#40;</span><span style="color: #003399;">Properties</span> props<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>props.<span style="color: #006633;">getProperty</span><span style="color: #009900;">&#40;</span>MY_PROPERTY<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// ici on utilise cette propriété...</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div>
</pre>
<p>Le test unitaire est tout naturellement :</p>
<pre>
<div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> testNullProperty<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #003399;">Properties</span> properties <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">Properties</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; assertNotNull<span style="color: #009900;">&#40;</span>properties<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; assertNull<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;property must be null&quot;</span>, properties.<span style="color: #006633;">getProperty</span><span style="color: #009900;">&#40;</span>MY_PROPERTY<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; myClassInstance.<span style="color: #006633;">initialize</span><span style="color: #009900;">&#40;</span>properties<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div>
</pre>
<p>Pour résumer, on teste si une instance fraichement créée est non-nulle, tout en vérifiant qu&#8217;elle ne contient pas encore la propriété&#8230; Quant à la méthode <code class="codecolorer java default"><span class="java">initialize<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span></span></code> qui est censée faire l&#8217;objet du test, certes on l&#8217;appelle mais on ne fait aucune vérification dessus. Bon, après tout le test passe, c&#8217;est le principal non ?<br />
Ce test n&#8217;est d&#8217;ailleurs pas isolé, plusieurs autres tests vérifient de la même façon la non-présence dans <code class="codecolorer java default"><span class="java">properties</span></code> d&#8217;autres propriétés utilisées dans <code class="codecolorer java default"><span class="java">initialize<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span></span></code> <img src='http://blog.excilys.com/wp-includes/images/smilies/icon_biggrin.gif' alt=':-D' class='wp-smiley' /> .</p>
<h4>Double fail inversé</h4>
<pre>
<div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">myVar <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>myMap <span style="color: #339933;">!=</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">?</span> <span style="color: #0000ff;">&quot;&quot;</span> <span style="color: #339933;">:</span> myMap.<span style="color: #006633;">get</span><span style="color: #009900;">&#40;</span>myField<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></td></tr></tbody></table></div>
</pre>
<p>Non seulement on n&#8217;a pas la valeur attendue, mais en plus on aura forcément une NullPointerException si <code class="codecolorer java default"><span class="java">myMap</span></code> vaut null <img src='http://blog.excilys.com/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' /> .</p>
<h4>True or false?</h4>
<pre>
<div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br /></div></td><td><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">boolean</span> superComplexLogic<span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">boolean</span> value<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">boolean</span> ret<span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">false</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">if</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span>getValue2<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&amp;&amp;</span> value<span style="color: #009900;">&#41;</span> <span style="color: #339933;">||</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>getValue2<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&amp;&amp;</span> <span style="color: #339933;">!</span>value<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> ret<span style="color: #339933;">=</span><span style="color: #000066; font-weight: bold;">true</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> ret<span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div>
</pre>
<p>Pourquoi faire simple ? Un <code class="codecolorer java default"><span class="java"><span style="color: #000000; font-weight: bold;">return</span> <span style="color: #009900;">&#40;</span>getValue2<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">==</span> value<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></span></code> aurait été tellement banal !</p>
<h4>TODO != Tout doux</h4>
<pre>
<div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br /></div></td><td><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #666666; font-style: italic;">// TODO en lot 8</span><br />
<span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;TODO&quot;</span>.<span style="color: #006633;">equals</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;TODO1&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #666666; font-style: italic;">// ...</span><br />
<span style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div>
</pre>
<p>Sympathique cette façon d&#8217;éviter que du code soit executé, non ? <img src='http://blog.excilys.com/wp-includes/images/smilies/icon_razz.gif' alt=':-P' class='wp-smiley' /> </p>
<h4>100% de couverture de tests !</h4>
<pre>
<div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br /></div></td><td><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">enum</span> MyEnum <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; MY_CONSTANT<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;O&quot;</span><span style="color: #009900;">&#41;</span>,<br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;">//...</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #666666; font-style: italic;">// Et le test associé :</span><br />
@Test<br />
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> testMyConstant<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; assertEquals<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;O&quot;</span>, MyEnum.<span style="color: #006633;">MY_CONSTANT</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div>
</pre>
<p>Au moins, si on fait une faute de frappe en écrivant l&#8217;enum, ce test le verra tout de suite <img src='http://blog.excilys.com/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
<h4>L&#8217;opération a échoué avec succès !</h4>
<pre>
<div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br /></div></td><td><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #666666; font-style: italic;">//succes - Recuperer la liste à réemettre.</span><br />
logger.<span style="color: #006633;">logError</span><span style="color: #009900;">&#40;</span>ServiceLogKeys.<span style="color: #006633;">SUCCESS_CODE</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></td></tr></tbody></table></div>
</pre>
<h4>Conclusion</h4>
<p>J&#8217;espère que ce petit moment de détente vous a plus, si c&#8217;est le cas nous allons essayer de motiver les troupes d&#8217;Excilys pour publier des articles collaboratifs de ce genre de temps en temps. Si vous avez aussi des exemples de LOLcode, n&#8217;hésitez pas à vous lacher dans les comms (attention aux clauses de non divulgation tout de même) <img src='http://blog.excilys.com/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> .</p>
<img src="http://feeds.feedburner.com/~r/blogexcilyscom/~4/4dQl3q60IJw" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.excilys.com/2010/06/14/un-peu-de-lolcode/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://blog.excilys.com/2010/06/14/un-peu-de-lolcode/</feedburner:origLink></item>
		<item>
		<title>Il y a toujours de la lumière chez Liferay Portal</title>
		<link>http://feedproxy.google.com/~r/blogexcilyscom/~3/zE6t5DcI3EA/</link>
		<comments>http://blog.excilys.com/2010/05/31/il-y-a-toujours-de-la-lumiere-chez-liferay-portal/#comments</comments>
		<pubDate>Mon, 31 May 2010 21:59:15 +0000</pubDate>
		<dc:creator>Alexis THOMAS</dc:creator>
				<category><![CDATA[Non classé]]></category>
		<category><![CDATA[Actualité]]></category>
		<category><![CDATA[IDE]]></category>
		<category><![CDATA[Liferay]]></category>
		<category><![CDATA[Liferay IDE]]></category>
		<category><![CDATA[Liferay Portal]]></category>
		<category><![CDATA[Portal]]></category>

		<guid isPermaLink="false">http://blog.excilys.com/?p=1924</guid>
		<description><![CDATA[Ce billet va s&#8217;attacher à reprendre les actualités récentes et importantes liées au portail Liferay qui ont marqué le début de l&#8217;année 2010. Mon constat étant que ces dernières sont passées assez inaperçues pour nombre d&#8217;entre nous et ont été peu ou pas commentées, en français notamment.
Par ordre chronologique :

février 2010 : version 6 de [...]]]></description>
			<content:encoded><![CDATA[<p>Ce billet va s&#8217;attacher à reprendre les actualités récentes et importantes liées au portail <a href="http://www.liferay.com/" target="_blank"><strong>Liferay</strong></a> qui ont marqué le début de l&#8217;année 2010. Mon constat étant que ces dernières sont passées assez inaperçues pour nombre d&#8217;entre nous et ont été peu ou pas commentées, en français notamment.</p>
<p>Par ordre chronologique :</p>
<ul>
<li>février 2010 : version 6 de Liferay Portal en approche</li>
<li>avril 2010 : Liferay Portal fête ses 10 ans</li>
<li>mai 2010 : sortie théorique de Liferay IDE 1.0</li>
</ul>
<div id="attachment_1933" class="wp-caption aligncenter" style="width: 310px"><a href="http://blog.excilys.com/wp-content/uploads/2010/05/Liferay_logo-large.png"><img class="size-medium wp-image-1933" src="http://blog.excilys.com/wp-content/uploads/2010/05/Liferay_logo-large-300x86.png" alt="Logo Liferay large" width="300" height="86" /></a><p class="wp-caption-text">Liferay pour la vie</p></div>
<p><span id="more-1924"></span></p>
<h3>Liferay Portal 6 annoncé</h3>
<p>En février dernier, Paul Hinz a dévoilé l&#8217;information que la prochaine version serait numérotée 6 et non pas 5.3 comme nous avions pu le penser. En effet, depuis quelques temps déjà, Liferay Portal 5.2 (plus précisément 5.2.3) est la dernière version officielle. La numérotation en 5.3 était par exemple utilisée dans le <a href="http://issues.liferay.com/secure/Dashboard.jspa" target="_blank">Jira de Liferay</a> pour désigner la version suivante corrigeant une anomalie. Depuis la numérotation dans Jira a bien sûr été corrigée <img src='http://blog.excilys.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> . Ce choix vient du fait qu&#8217;après avoir revu l&#8217;ensemble des fonctionnalités et améliorations futures prévues dans la stratégie de développement du portail, il a été décidé que la <em>release</em> suivante profiterait d&#8217;un changement de numéro de version majeur.</p>
<p>Cette version avait pour nom de code <em>Bunyan</em> en interne et sera donc officiellement <strong>Liferay Portal 6</strong>.</p>
<p>L&#8217;annonce officielle postée sur le blog de Liferay mentionnait les éléments suivants comme étant majeurs et à surveiller :</p>
<table style="margin-left: 12%; width: 75%;">
<tbody>
<tr>
<td>Gestion des contenus et connaissances</p>
<ul>
<li>Partage de contenu</li>
<li>Tags et catégories</li>
<li>Attributs <em>customs</em></li>
<li>Rapports d&#8217;utilisation</li>
<li>Vue de différences</li>
<li>Gestion des droits</li>
<li>Plugin de Base de connaissance</li>
<li>Workflow intégré</li>
</ul>
</td>
<td>Gestion de la plateforme</p>
<ul>
<li>Monitoring de performance des portlets</li>
<li>Audit</li>
<li>Analyse et suivi</li>
<li>Liaison de <em>clusters</em></li>
<li>Partitionnement horizontal (<a href="http://en.wikipedia.org/wiki/Shard_%28database_architecture%29" target="_blank"><em>sharding</em></a>)</li>
</ul>
</td>
</tr>
<tr>
<td>Extensions et intégration</p>
<ul>
<li>Framework de gestion des droits</li>
<li>Framework <a href="http://alloy.liferay.com/" target="_blank">Alloy UI</a></li>
<li>Moteur de règles de personnalisation</li>
<li>Framework de scripting</li>
<li>Accès aux services Liferay depuis les portlets</li>
<li>Intégration avec des systèmes externes</li>
</ul>
</td>
<td>UI et utilisation</p>
<ul>
<li>Navigation simplifiée</li>
<li>UI améliorée pour la gestion de documents</li>
<li>Création de page en 1 clic</li>
<li>Création de communauté en 1 clic</li>
<li>Édition de contenu simple</li>
</ul>
</td>
</tr>
</tbody>
</table>
<p>Parmi ces éléments, on peut noter l&#8217;amélioration de l&#8217;intégration des <em>workflows</em> et pour ce faire nous devrions bénéficier du support de <a href="http://www.jboss.org/jbpm/" target="_blank">jBPM</a>. Concernant la bibliothèque de documents, celle-ci devrait pouvoir s&#8217;intégrer avec <a href="http://www.emc.com/domains/documentum/index.htm" target="_blank">Documentum</a>, <a href="http://www.oasis-open.org/committees/tc_home.php?wg_abbrev=cmis" target="_blank">CMIS</a> et <a href="http://sharepoint.microsoft.com" target="_blank">Sharepoint</a> par exemple.</p>
<p><strong>Liferay Portal 6</strong> va se baser sur des technologies JEE courantes et chercher à ajouter ou simplement améliorer leur prise en charge, au cœur du portail ou/et pour l&#8217;ouvrir aux systèmes externes :</p>
<ul>
<li><a href="http://fr.wikipedia.org/wiki/Java_Persistence_API" target="_blank">JPA</a> et <a href="http://java.sun.com/javase/technologies/core/mntr-mgmt/javamanagement/" target="_blank">JMX</a> seront intégrés, <a href="http://oauth.net/" target="_blank">OAuth</a> sera amélioré, le support de <a href="http://maven.apache.org/" target="_blank">Maven</a> devrait être presque natif</li>
<li>les plugins pourront exposer des web services en <a href="http://www.json.org/" target="_blank">JSON</a> et <a href="http://www.w3.org/TR/soap/" target="_blank">SOAP</a></li>
<li>intégration avec <a href="http://fr.openoffice.org/" target="_blank">OpenOffice</a>, <a href="http://www.google.com/apps/" target="_blank">Google Apps</a>, <a href="http://jasperreports.sourceforge.net/" target="_blank">Jasper</a>, <a href="http://www.eclipse.org/birt/" target="_blank">BIRT</a></li>
<li>possibilité de changer de moteur de BPM (utiliser <a href="http://www.intalio.com/" target="_blank">Intalio</a> à la place de jBPM par exemple)</li>
<li>intégration avec <a href="http://www.netvibes.com/" target="_blank">NetVibes</a>, <a href="http://www.opensocial.org/" target="_blank">OpenSocial</a>, SEO, <a href="http://caldav.calconnect.org/" target="_blank">CalDAV</a>, <a href="http://www.salesforce.com/fr/" target="_blank">SalesForce</a>, <a href="http://vaadin.com/" target="_blank">Vaadin</a></li>
<li>formulaires et listes dynamiques</li>
<li>gestionnaires de tâches et de contacts</li>
</ul>
<h4>Premiers retours sur Liferay Portal 6 <em>preview</em> / RC</h4>
<p>Dans un premier temps, cette version 6 n&#8217;a été mise à disposition que par l&#8217;intermédiaire d&#8217;une <em>preview</em>. Le site officiel n&#8217;en faisait pas mention, mais SouceForge et les <em>Nightly Builds</em> commençaient à diffuser ces premières ébauches à tester.</p>
<p>Deux mois plus tard, en avril, c&#8217;est au tour de la <em>Release Candidate</em> d&#8217;avoir été officialisée. Elle incluait de nombreux correctifs et la plupart des portlets finales qui manquaient dans la <em>preview</em>, dont la traditionnelle application de démarrage <em>7Cogs</em>.</p>
<p>Depuis la sortie de la version RC de Liferay Portal 6, la page de téléchargement habituelle prépare les utilisateurs au changement à venir. En effet, vous pouvez toujours choisir de récupérer un <em>bundle</em> basé sur Liferay Portal 5.2.3 CE, mais vous pouvez également vous essayer à la RC. Une liste déroulante proposant les <em>bundles</em> mis à jour pointe ainsi sur la dernière version officielle de Liferay Portal 6.</p>
<p>La première version RC numérotée 6.0.1 semble souffrir d&#8217;un nombre important de retours d&#8217;anomalies. Ceci explique surement en partie le retard qui commence à grandir pour la <em>release</em> finale et aussi la longue durée depuis laquelle nous attendons la sortie de la RC2. Cette deuxième RC devrait débloquer la situation, espérons-le.</p>
<p>Notons quand même que la <em>roadmap</em> initiale prévoyait une sortie finale de Liferay Portal 6 entre février et avril 2010 pour respectivement les versions Community Edition et Enterprise Edition. Il est maintenant souhaitable que toutes ces corrections de bugs qui se sont ajoutées permettent d&#8217;obtenir un portail avec une meilleure finition comparé aux versions précédentes <img src='http://blog.excilys.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> .</p>
<h3>Liferay Portal a 10 ans</h3>
<p>Le 23 avril dernier, Liferay nous a fait cadeau d&#8217;une belle newsletter intitulée  &#8216;10 Years of Open Source: Liferay in 2010&#8242;. En effet, la société s&#8217;est construite sur son portail et a su évoluer en trouvant les partenaires de poids nécessaires. Maintenant elle continue son chemin en profitant de son expérience.</p>
<p>Je vous retranscris ici le contenu de leur message :</p>
<blockquote><p>Cette année marque le 10ème anniversaire de Liferay Portal. Brian Chan a démarré le développement en 2000 et Liferay est très rapidement devenu la plateforme de premier choix pour construire des applications d&#8217;entreprises dynamiques et efficaces. Avec 3 millions de téléchargements, 250 000 déploiements et une communauté active d&#8217;environ 30 000 personnes, Liferay a connu une croissance explosive dans sa 11ème année.</p>
<div id="attachment_1932" class="wp-caption alignright" style="width: 140px"><a href="http://blog.excilys.com/wp-content/uploads/2010/05/Liferay_logo.png"><img class="size-full wp-image-1932" src="http://blog.excilys.com/wp-content/uploads/2010/05/Liferay_logo.png" alt="Logo Liferay" width="130" height="131" /></a><p class="wp-caption-text">Un éclat éternel ?</p></div>
<p>Cette année marque aussi le 6ème anniversaire de la société, basée sur l&#8217;open source, et Liferay célèbre plusieurs jalons :</p>
<ul>
<li>Des centaines de sociétés clientes comme Cisco Systems, Electronic Arts et Société Générale</li>
<li>Plus de 60 partenaires dans le réseau international</li>
<li>Reconnu deux ans de suite comme Visionnaire dans le Gartner’s Magic Quadrant</li>
<li>Forte croissance des revenus et du support présent dans les bureaux d&#8217;Amérique du nord, d&#8217;Europe, du Brésil, d&#8217;Inde et de Chine.</li>
</ul>
<p>Merci pour votre soutien et au plaisir de travailler à vos côtés en 2010 !</p></blockquote>
<p>Si nous reprenons un peu l&#8217;historique, voici ce qu&#8217;on pourrait obtenir :</p>
<ul>
<li>2000 : premiers développements par Brian Chan, pour proposer un portail d&#8217;entreprise pour les organismes à but non lucratif</li>
<li>2006 : création de la société Liferay Inc., et de la filiale Liferay GmbH en Allemagne</li>
<li>2007 : ouverture de nouveaux bureaux en Asie et en Espagne</li>
<li>2009 : création d&#8217;un bureau en Inde</li>
</ul>
<p>La croissance de Liferay s&#8217;est faite aussi grâce à des partenariats :</p>
<ul>
<li>ICEsoft Technologies, en juillet 2007, pour incorporer la technologie <a href="http://fr.wikipedia.org/wiki/Asynchronous_JavaScript_and_XML" target="_blank">Ajax</a></li>
<li>janvier 2008 : recrutement du <em>lead engineer</em> de <a href="http://jqueryui.com/" target="_blank">jQuery UI</a></li>
<li>Sun Microsystems, en mai 2008, pour un accord d&#8217;échange technologique</li>
<li>2009 : Liferay intègre le comité de spécification de <a href="http://www.oasis-open.org/committees/tc_home.php?wg_abbrev=cmis" target="_blank">Oasis  CMIS</a></li>
<li>IT Mill Ltd., en octobre 2009, pour travailler autour de leur librairie de UI nommée <a href="http://vaadin.com/home" target="_blank">Vaadin</a></li>
</ul>
<h3>Liferay IDE 1.0 en vue</h3>
<p>Gregory Amerson a rejoint l&#8217;équipe Liferay à Los Angeles en février 2010. Son expérience de <em>senior developer</em> sur MyEclipse l&#8217;a propulsé au poste de <em>software engineer</em> en charge du développement de l&#8217;outillage autour du portail et plus spécifiquement basé sur Eclipse. La première release de Liferay IDE devait se faire suivant un plan de 2 mois aboutissant sur la publication de la version 1.0.</p>
<div id="attachment_2063" class="wp-caption alignright" style="width: 154px"><a href="http://blog.excilys.com/wp-content/uploads/2010/05/eclipse_pos_logo_fc_sm.jpg"><img class="size-full wp-image-2063" src="http://blog.excilys.com/wp-content/uploads/2010/05/eclipse_pos_logo_fc_sm.jpg" alt="Logo Eclipse" width="144" height="144" /></a><p class="wp-caption-text">Le jour et la nuit</p></div>
<p>Depuis avril, le développement suit son court et les premiers <em>builds</em> sont testables pour les plus motivés. Six vidéos de démonstration ont été publiées et présentent certaines des fonctionnalités qui seront présentes de façon certaine dans la version finale :</p>
<ol>
<li><a href="http://www.liferay.com/c/document_library/get_file?p_l_id=4616001&amp;groupId=4615837&amp;folderId=4933105&amp;name=DLFE-40604.swf">Create new plug-in project</a></li>
<li><a href="http://www.liferay.com/c/document_library/get_file?p_l_id=4616001&amp;groupId=4615837&amp;folderId=4933105&amp;name=DLFE-40609.swf">Portlet Project Deployment</a></li>
<li><a href="http://www.liferay.com/c/document_library/get_file?p_l_id=4616001&amp;groupId=4615837&amp;folderId=4933105&amp;name=DLFE-40608.swf">New Portlet Wizard</a></li>
<li><a href="http://www.liferay.com/c/document_library/get_file?p_l_id=4616001&amp;groupId=4615837&amp;folderId=4933105&amp;name=DLFE-40607.swf">New Hook Wizard</a></li>
<li><a href="http://www.liferay.com/c/document_library/get_file?p_l_id=4616001&amp;groupId=4615837&amp;folderId=4933105&amp;name=DLFE-40605.swf">More Hook Wizard</a></li>
<li><a href="http://www.liferay.com/c/document_library/get_file?p_l_id=4616001&amp;groupId=4615837&amp;folderId=4933105&amp;name=DLFE-40606.swf">Plug-in Package Editor</a></li>
</ol>
<p>La date du 12 mai avait été donnée pour la sortie de la version 1.0 finale. Plus de 2 semaines plus tard, force est de constater que nous devons encore patienter un peu.</p>
<h4>Dans les cartons de Liferay IDE</h4>
<p>Liferay IDE 1.0 proposera la gestion du serveur Liferay Portal, la création d&#8217;un projet, des éditeurs pour les descripteurs spécifiques et des <em>wizards</em> de création d&#8217;artefact de portail, le tout conforme à l&#8217;état de l&#8217;art des pratiques que chaque développeur utilisant Liferay doit répéter sans cesse dans son environnement de développement personnel.</p>
<p>La page du wiki officiel qui présente Liferay IDE nous donne quelques éléments de détails :</p>
<blockquote><p>Le but de Liferay IDE est de fournir l&#8217;outillage basé sur Eclipse le plus abouti qui soit pour l&#8217;environnement de développement de Liferay Portal à destination des <span style="text-decoration: underline;">versions 6.0 et supérieur</span>.</p>
<p>Liferay IDE viendra complémenter l&#8217;existant d&#8217;une façon très similaire à ce que fait SpringSource Tool Suite pour la plateforme Spring.</p>
<p>Livrables produits sans aucune différence de fonctionnalité :</p>
<ol>
<li>Liferay IDE All-in-one bundle (incluant par exemple un JRE, un pack Liferay, la JavaDoc, des packages complémentaires de sources du portail, etc.)</li>
<li>Liferay IDE plugins bundle pour Eclipse Galileo JEE (3.5.x)</li>
<li>Update site pour Eclipse Galileo</li>
</ol>
<p>Priorités :</p>
<ol>
<li>Pouvoir démarrer facilement sur la plateforme Liferay</li>
<li>Simplifier ou automatiser les tâches fréquentes et ennuyeuses</li>
<li>Intégrer le Liferay Plugins SDK</li>
<li>Développer, déployer et débugger les plugins Liferay facilement</li>
</ol>
<p>Disponible entre autres pour la version 1.0 :</p>
<ul>
<li>Importer, créer et travailler sur des projets Eclipse de plugins Liferay directement</li>
<li>Prendre en charge le Liferay Portal depuis l&#8217;IDE</li>
<li>Nouveaux wizards pour automatiser les créations répétitives de contenus</li>
<li>Assistance à la saisie</li>
<li>Templates personnalisés</li>
</ul>
<p>Prévu pour les versions suivantes notamment :</p>
<ul>
<li>Gestion avancée du Plugins SDK et du bundle Liferay Portal utilisés</li>
<li>Projets pour les Theme et Layout Template</li>
<li>Éditeurs améliorés et validation des structures saisies</li>
<li>Gestion automatique des dépendances</li>
<li>Log d&#8217;activité du serveur</li>
</ul>
</blockquote>
<h4>Premiers retours sur Liferay IDE 1.0 preview</h4>
<p>La communauté a fait part de son intérêt pour cet IDE qui était très attendu. Pour la version 1.0, Eclipse est la priorité absolue et donc seul ciblé. Par la suite, les autres IDE devraient pouvoir recevoir une prise en charge par le biais de plugins officiels. Un travail notable d&#8217;intégration pour NetBeans ayant déjà été entrepris (cf. <a href="http://contrib.netbeans.org/portalpack/" target="_blank">Portal Pack</a>), ce dernier devrait être géré rapidement. Quant à IntelliJ IDEA, il sera aussi supporté à l&#8217;avenir.</p>
<p>L&#8217;équipe reste à l&#8217;écoute des besoins des utilisateurs et par exemple, se montre intéressée lorsqu&#8217;est évoqué le &#8220;besoin&#8221; de gérer la prise en compte native de JSF 2.0 pour les portlets directement depuis l&#8217;IDE. D&#8217;autres idées émises concernent par exemple la gestion directe par l&#8217;IDE d&#8217;artefacts Maven spécifiques à Liferay pour donner suite au <a href="http://www.liferay.com/web/mika.koivisto/blog/-/blogs/liferay-maven-sdk" target="_blank">Liferay Maven SDK</a>.</p>
<p>Pour tester la version de preview, Gregory Amerson a mis en place un <em>update site</em> à ajouter dans votre Eclipse :</p>
<p style="text-align: center;"><span style="text-decoration: underline;">http://gregamerson.com/liferay-ide/updates/latest/</span></p>
<p>Fin mai, seule la version 6.0.1 du portail (Liferay Portal 6 RC 1) est officiellement disponible au téléchargement depuis <a href="http://sourceforge.net/projects/lportal/" target="_blank">SourceForge</a>. Ceci pose problème si vous tentez d&#8217;utiliser la version <em>preview</em> de Liferay IDE qui demande que votre portail soit au minimum en version 6.0.2. La seule solution semble donc être de se tourner vers les <em>Nightly Builds</em> du portail en attendant que la RC 2 soit publiée officiellement. L&#8217;url pour récupérer ces builds est :</p>
<p style="text-align: center;"><span style="text-decoration: underline;">http://releases.liferay.com/portal/nightly/</span></p>
<p>D&#8217;après Gregory Amerson, le <em>build</em> Liferay Portal 6 RC 2 sera publié d&#8217;ici peu et Liferay IDE 1.0 devrait suivre de près. Plus que quelques jours à attendre donc !? <img src='http://blog.excilys.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<h3>Conclusion</h3>
<p>Voici donc quelques actualités majeures dans le &#8220;petit&#8221; monde de <strong>Liferay</strong> qui méritaient qu&#8217;on s&#8217;y attarde un peu. Et puisque les sujets sont encore bien chauds, nous devrions voir arriver très rapidement les annonces des <em>releases</em> finales. Et encore d&#8217;autres surprises peut être ? <img src='http://blog.excilys.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>Pour terminer et ne faire que les mentionner, <a href="http://www.jboss.org/gatein" target="_blank">GateIn</a> et <a href="http://www.exoplatform.com/" target="_blank">eXo Platform</a> sont les premiers à faire beaucoup parler d&#8217;eux ces derniers temps parmi les éditeurs de portails, donc <a href="http://www.liferay.com/" target="_blank"><strong>Liferay</strong></a> a tout intérêt à se montrer entreprenant pour ne pas se faire distancer !</p>
<h3>Références</h3>
<ul>
<li>Billets de Paul Hinz : <a href="http://www.liferay.com/web/paul.hinz/blog" target="_blank">http://www.liferay.com/web/paul.hinz/blog</a></li>
<li>Billets de Brian Chan : <a href="http://www.liferay.com/web/brian.chan/blog" target="_blank">http://www.liferay.com/web/brian.chan/blog</a></li>
<li>Wiki Liferay : <a href="http://www.liferay.com/community/wiki/" target="_blank">http://www.liferay.com/community/wiki/</a></li>
<li>Billets de Gregory Amerson : <a href="http://www.liferay.com/web/gregory.amerson/blog" target="_blank">http://www.liferay.com/web/gregory.amerson/blog</a></li>
</ul>
<img src="http://feeds.feedburner.com/~r/blogexcilyscom/~4/zE6t5DcI3EA" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.excilys.com/2010/05/31/il-y-a-toujours-de-la-lumiere-chez-liferay-portal/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		<feedburner:origLink>http://blog.excilys.com/2010/05/31/il-y-a-toujours-de-la-lumiere-chez-liferay-portal/</feedburner:origLink></item>
		<item>
		<title>Blazé du remoting ? Utilisez Spring-flex !</title>
		<link>http://feedproxy.google.com/~r/blogexcilyscom/~3/a8fLHyENToU/</link>
		<comments>http://blog.excilys.com/2010/05/19/blaze-du-remoting-utilisez-spring-flex/#comments</comments>
		<pubDate>Wed, 19 May 2010 08:00:20 +0000</pubDate>
		<dc:creator>Bastien JANSEN</dc:creator>
				<category><![CDATA[Non classé]]></category>
		<category><![CDATA[blazeds]]></category>
		<category><![CDATA[flex]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[open source]]></category>
		<category><![CDATA[remoting]]></category>
		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://blog.excilys.com/?p=1110</guid>
		<description><![CDATA[Introduction

Suite à la mise en place d&#8217;un environnement de développement Flex en Open Source, je vous propose aujourd&#8217;hui de simplifier l&#8217;utilisation de BlazeDS grâce à Spring BlazeDS Integration (Spring-flex).
La description suivante, traduite de l&#8217;introduction faite sur le site officiel, résume bien les buts recherchés :
 
Spring BlazeDS Integration est une réponse à une demande de [...]]]></description>
			<content:encoded><![CDATA[<h3>Introduction</h3>
<p><a href="http://www.springsource.org"><img class="size-full wp-image-1989 alignright" title="Spring" src="http://blog.excilys.com/wp-content/uploads/2010/01/spring1.png" alt="Logo Spring" width="118" height="52" /></a></p>
<p>Suite à la mise en place d&#8217;un <a href="http://blog.excilys.com/2010/01/20/open-source-flex-development-stack/">environnement de développement Flex</a> en Open Source, je vous propose aujourd&#8217;hui de simplifier l&#8217;utilisation de <a href="http://opensource.adobe.com/wiki/display/blazeds/BlazeDS/">BlazeDS</a> grâce à <a href="http://www.springsource.org/spring-flex">Spring BlazeDS Integration</a> (Spring-flex).</p>
<p>La description suivante, traduite de l&#8217;introduction faite sur le site officiel, résume bien les buts recherchés :</p>
<blockquote><p><em> </em></p>
<p>Spring BlazeDS Integration est une réponse à une demande de la communauté qui souhaitait avoir une solution pour construire des <strong>RIA propulsées par Spring</strong>, utilisant Adobe <strong>Flex </strong>pour la technologie client. [...] Bien qu&#8217;il était possible d&#8217;utiliser BlazeDS pour se connecter à des services gérés par Spring, ce n&#8217;était pas réalisable de manière &#8220;naturelle&#8221; pour un développeur Spring, nécessitant d&#8217;avoir à maintenir une <strong>configuration XML BlazeDS séparée</strong>. Spring BlazeDS Integration change tout cela en transformant le <strong>MessageBroker</strong> de BlazeDS en un objet géré par Spring, ouvrant des perspectives vers une <strong>intégration plus complète</strong> qui suit le &#8220;Spring way&#8221;.</p></blockquote>
<p><em> </em></p>
<p>Dans cet article, nous allons voir les principes de base de Spring BlazeDS Integration : <strong>configuration</strong>, <strong>exposition </strong>des services et <strong>consommation </strong>par un client Flex. Un projet est réalisé en parallèle pour illustrer la théorie ; les exemples de code suivant en sont tirés. Le <a href="http://blog.excilys.com/wp-content/uploads/2010/01/Spring-BlazeDS-integration.zip">code source final</a> est disponible à la fin de cet article.  Si vous n&#8217;avez pas encore lu le <a href="http://blog.excilys.com/2010/01/20/open-source-flex-development-stack/">précédent article</a>, je vous invite à le faire car il explique de nombreuses notions qui seront réutilisées ici.<span id="more-1110"></span></p>
<h3>Mise en place de la webapp</h3>
<h4>C&#8217;est bien Mave(i)n(e)&#8230;</h4>
<p>Une fois n&#8217;est pas coutume, nous allons utiliser Maven 2 pour créer le squelette d&#8217;application web qui sera utilisée par le client Flex :</p>
<pre>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">mvn archetype:create -DgroupId=com.excilys.java -DartifactId=SimpleSpringFlex -DarchetypeArtifactId=maven-archetype-webapp</div></td></tr></tbody></table></div>
</pre>
<h4>Retour aux sources</h4>
<p>Ajoutons tout de suite les bonnes dépendances vers Spring-Flex :</p>
<pre>
<div class="codecolorer-container xml default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br /></div></td><td><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;dependency<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;groupId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>org.springframework.flex<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/groupId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;artifactId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>spring-flex<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/artifactId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;version<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>1.0.1.RELEASE<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/version<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/dependency<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></td></tr></tbody></table></div>
</pre>
<p>Commençons par adapter le descripteur de déploiement <strong>web.xml <span style="font-weight: normal;">:</span></strong></p>
<pre>
<div class="codecolorer-container xml default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br /></div></td><td><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;web-app</span> <span style="color: #000066;">version</span>=<span style="color: #ff0000;">&quot;3.0&quot;</span> <span style="color: #000066;">xmlns</span>=<span style="color: #ff0000;">&quot;http://java.sun.com/xml/ns/javaee&quot;</span> <span style="color: #000066;">xmlns:xsi</span>=<span style="color: #ff0000;">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span> <span style="color: #000066;">xsi:schemaLocation</span>=<span style="color: #ff0000;">&quot;http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;display-name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Simple Flex Remoting with Spring-Flex<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/display-name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;servlet<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;servlet-name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>dispatcher<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/servlet-name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;servlet-class<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>org.springframework.web.servlet.DispatcherServlet<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/servlet-class<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;load-on-startup<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>1<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/load-on-startup<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/servlet<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<br />
&nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;servlet-mapping<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;url-pattern<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>/messagebroker/*<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/url-pattern<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;servlet-name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>dispatcher<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/servlet-name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/servlet-mapping<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/web-app<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></td></tr></tbody></table></div>
</pre>
<p>Comme dans l&#8217;article précédent, nous mappons le pattern <strong>/messagebroker/*</strong> sur une servlet, sauf que maintenant ce n&#8217;est plus une <strong>MessageBrokerServlet</strong>, mais une <strong>DispatcherServlet </strong>Spring. Le travail de Spring va donc commencer ici. Profitons de la convention du framework qui ira chercher par défaut la configuration du conteneur Spring associée à cette servlet dans le fichier <strong>WEB-INF/dispatcher-servlet.xml</strong> :</p>
<pre>
<div class="codecolorer-container xml default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br /></div></td><td><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;?xml</span> <span style="color: #000066;">version</span>=<span style="color: #ff0000;">&quot;1.0&quot;</span> <span style="color: #000066;">encoding</span>=<span style="color: #ff0000;">&quot;UTF-8&quot;</span><span style="color: #000000; font-weight: bold;">?&gt;</span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;beans</span> <span style="color: #000066;">xmlns</span>=<span style="color: #ff0000;">&quot;http://www.springframework.org/schema/beans&quot;</span></span><br />
<span style="color: #009900;"> &nbsp; &nbsp;<span style="color: #000066;">xmlns:flex</span>=<span style="color: #ff0000;">&quot;http://www.springframework.org/schema/flex&quot;</span></span><br />
<span style="color: #009900;"> &nbsp; &nbsp;<span style="color: #000066;">xmlns:xsi</span>=<span style="color: #ff0000;">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span><br />
<span style="color: #009900;"> &nbsp; &nbsp;<span style="color: #000066;">xsi:schemaLocation</span>=<span style="color: #ff0000;">&quot;</span><br />
<span style="color: #009900;"> &nbsp; &nbsp; &nbsp; &nbsp;http://www.springframework.org/schema/beans</span><br />
<span style="color: #009900;"> &nbsp; &nbsp; &nbsp; &nbsp;http://www.springframework.org/schema/beans/spring-beans-2.5.xsd</span><br />
<span style="color: #009900;"> &nbsp; &nbsp; &nbsp; &nbsp;http://www.springframework.org/schema/flex</span><br />
<span style="color: #009900;"> &nbsp; &nbsp; &nbsp; &nbsp;http://www.springframework.org/schema/flex/spring-flex-1.0.xsd&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
<br />
&nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;flex:messagebroker</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/beans<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></td></tr></tbody></table></div>
</pre>
<p>Par rapport à une configuration classique, notez l&#8217;inclusion de l&#8217;espace de nommage <strong>&#8220;flex&#8221;</strong>, qui va rendre disponible la balise <strong>messagebroker</strong>. Celle-ci va nous permettre de créer un <em>managed bean</em> de type <strong>MessageBroker</strong>, qui va gérer les flux AMF (là aussi on profite de la configuration par défaut du bean, notamment pour le nom du fichier de configuration <strong>services-config.xml</strong>).</p>
<div id="attachment_1990" class="wp-caption aligncenter" style="width: 220px"><img class="size-medium wp-image-1990  " title="Mr Bean" src="http://blog.excilys.com/wp-content/uploads/2010/01/bean-210x300.jpg" alt="" width="210" height="300" /><p class="wp-caption-text">Exemple de Bean non managé par Spring</p></div>
<h3>Création des services</h3>
<p>Dans cette partie, nous allons faire du Java &#8220;classique&#8221;. Le but de la webapp créée au tout début de l&#8217;article est d&#8217;exposer des services à notre client Flex. Créons donc notre service, qui va permettre d&#8217;additioner deux nombres (calcul nécessitant de grosses ressources type cluster <img src='http://blog.excilys.com/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' /> ) :</p>
<pre>
<div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br /></div></td><td><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">package</span> <span style="color: #006699;">com.excilys.java.springflex.service</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> MathService <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">int</span> add<span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">int</span> a, <span style="color: #000066; font-weight: bold;">int</span> b<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">int</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">2</span><span style="color: #339933;">*</span><span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">double</span><span style="color: #009900;">&#41;</span>a<span style="color: #339933;">/</span>b<span style="color: #009900;">&#41;</span> <span style="color: #339933;">*</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">double</span><span style="color: #009900;">&#41;</span>b<span style="color: #339933;">/</span><span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">int</span><span style="color: #009900;">&#41;</span><span style="color: #003399;">Math</span>.<span style="color: #006633;">sqrt</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">4</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">+</span> <span style="color: #009900;">&#40;</span>b <span style="color: #339933;">&lt;&lt;</span> <span style="color: #cc66cc;">2</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">/</span> <span style="color: #cc66cc;">4</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// Addition standard.</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div>
</pre>
<h4><strong>Exposition (gratuite) de services</strong></h4>
<p>Il nous reste maintenant à rendre ce service accessible à notre application Flex. En utilisant BlazeDS directement, il faudrait ajouter chaque service dans le fichier <strong>WEB-INF/flex/services-config.xml</strong>. Avec Spring-flex, nous allons pouvoir minimiser cette configuration :</p>
<pre>
<div class="codecolorer-container xml default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br /></div></td><td><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;services-config<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;services<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;default-channels<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;channel</span> <span style="color: #000066;">ref</span>=<span style="color: #ff0000;">&quot;my-amf&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/default-channels<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/services<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;channels<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;channel-definition</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;my-amf&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;endpoint</span> <span style="color: #000066;">url</span>=<span style="color: #ff0000;">&quot;http://{server.name}:{server.port}/{context.root}/messagebroker/amf&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/channel-definition<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/channels<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/services-config<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></td></tr></tbody></table></div>
</pre>
<p>On se contente de dire que les services utiliseront par défaut le channel <strong>&#8220;my-amf&#8221;</strong>, avec l&#8217;<em>endpoint<strong> </strong></em><strong>/mesagebroker/amf</strong>. Pour exposer notre service, nous pouvons utiliser l&#8217;annotation <strong>@RemotingDestination <span style="font-weight: normal;">:</span></strong></p>
<pre>
<div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br /></div></td><td><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #666666; font-style: italic;">//...</span><br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.flex.remoting.RemotingDestination</span><span style="color: #339933;">;</span><br />
<br />
@RemotingDestination<br />
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> MathService <span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #666666; font-style: italic;">//...</span><br />
<span style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div>
</pre>
<p>Pour que ces annotations soient prises en compte, il faut bien évidemment utiliser la balise <strong>component-scan</strong> dans <strong>dispatcher-servlet.xml</strong> :</p>
<pre>
<div class="codecolorer-container xml default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;bean</span> <span style="color: #000066;">xmlns:context</span>=<span style="color: #ff0000;">&quot;http://www.springframework.org/schema/context&quot;</span> ...<span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;context:component-scan</span> <span style="color: #000066;">base-package</span>=<span style="color: #ff0000;">&quot;com.excilys.java.springflex&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/bean<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></td></tr></tbody></table></div>
</pre>
<h3>Appels depuis le frontend Flex</h3>
<p>Nos services sont exposés, nous pouvons maintenant les consommer depuis du code Flex. Pour cela, nous utiliserons un RemoteObject de la même manière que dans l&#8217;<a href="http://blog.excilys.com/2010/01/20/open-source-flex-development-stack/">article précédent</a>. Le channel &#8220;my-blazeds&#8221; utilisera l&#8217;URL du DispatcherServlet :</p>
<pre>
<div class="codecolorer-container xml default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br /></div></td><td><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;channel-definition</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;my-blazeds&quot;</span> <span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;endpoint</span> <span style="color: #000066;">uri</span>=<span style="color: #ff0000;">&quot;http://localhost:8080/SimpleSpringFlex/messagebroker/amf&quot;</span></span><br />
<span style="color: #009900;"> &nbsp; &nbsp; &nbsp;<span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;flex.messaging.endpoints.AMFEndpoint&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/channel-definition<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></td></tr></tbody></table></div>
</pre>
<p><span style="color: #ff0000;"> </span></p>
<div id="attachment_1995" class="wp-caption aligncenter" style="width: 826px"><img class="size-full wp-image-1995 " title="Spring-Flex en action" src="http://blog.excilys.com/wp-content/uploads/2010/01/difficult-operation.png" alt="" width="816" height="276" /><p class="wp-caption-text">Spring-Flex en action</p></div>
<h3>Et après ?</h3>
<p>Ajouter d&#8217;autres services (soustraction, multiplication, &#8230;) consiste à ajouter des méthodes dans MathService. Pour exposer d&#8217;autres classes de services, il suffit de les annoter avec un <code class="codecolorer java default"><span class="java">@RemotingDestination</span></code>.</p>
<p>Si vos services  nécessitent une authentification préalable, il est possible de <a href="http://static.springsource.org/spring-flex/docs/1.0.x/reference/html/ch04.html">sécuriser les destinations avec Spring Security</a>.</p>
<p>Enfin, pour la partie <em>messaging</em>, Spring BlazeDS Integration facilite <a href="http://static.springsource.org/spring-flex/docs/1.0.x/reference/html/ch05.html">l&#8217;envoi de messages</a> entre clients Flex et/ou POJOs. Il est ainsi possible d&#8217;utiliser AMF ou JMS de manière similaire, grâce à une couche d&#8217;abstraction.</p>
<p>Nous venons de voir qu&#8217;une fois de plus, Spring nous propose un module assez simple d&#8217;utilisation qui permet de gagner en clarté de configuration et en rapidité d&#8217;exposition de services. La configuration XML est minimisée, les annotations font le reste. Et comme c&#8217;est bien pensé, ça s&#8217;intègre sans problème avec d&#8217;autres briques Spring liées par exemple à la sécurité. C&#8217;est-y pas beau çà ?</p>
<h3>Code source</h3>
<p>Pour bidouiller vous-même Spring-Flex, vous pouvez télécharger le <a href="http://blog.excilys.com/wp-content/uploads/2010/01/Spring-BlazeDS-integration.zip">code source du projet</a> réalisé dans cet article.</p>
<img src="http://feeds.feedburner.com/~r/blogexcilyscom/~4/a8fLHyENToU" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.excilys.com/2010/05/19/blaze-du-remoting-utilisez-spring-flex/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://blog.excilys.com/2010/05/19/blaze-du-remoting-utilisez-spring-flex/</feedburner:origLink></item>
		<item>
		<title>Compte-rendu du Paris JUG : soirée Build, Share &amp; Deploy</title>
		<link>http://feedproxy.google.com/~r/blogexcilyscom/~3/9W2x5lyQDLc/</link>
		<comments>http://blog.excilys.com/2010/05/14/compte-rendu-du-paris-jug-soiree-build-share-deploy/#comments</comments>
		<pubDate>Fri, 14 May 2010 13:41:03 +0000</pubDate>
		<dc:creator>Bastien JANSEN</dc:creator>
				<category><![CDATA[J'y étais !]]></category>
		<category><![CDATA[build]]></category>
		<category><![CDATA[déploiement]]></category>
		<category><![CDATA[dvcs]]></category>
		<category><![CDATA[git]]></category>
		<category><![CDATA[maven]]></category>
		<category><![CDATA[maven 3]]></category>
		<category><![CDATA[paris jug]]></category>
		<category><![CDATA[w3]]></category>
		<category><![CDATA[w3c]]></category>

		<guid isPermaLink="false">http://blog.excilys.com/?p=1935</guid>
		<description><![CDATA[Aujourd&#8217;hui, nous tentons une expérience : écrire un article à plusieurs. Mais plutôt que de s&#8217;abriter derrière un &#8220;nous&#8221; anonyme et sécurisant, nous (sic !) avons décidé de continuer à employer la première personne, en précisant qui est le locuteur lorsque c&#8217;était nécessaire. A vous de nous dire si vous appréciez le format   [...]]]></description>
			<content:encoded><![CDATA[<div class="note">Aujourd&#8217;hui, nous tentons une expérience : écrire un article à plusieurs. Mais plutôt que de s&#8217;abriter derrière un &#8220;nous&#8221; anonyme et sécurisant, nous (sic !) avons décidé de continuer à employer la première personne, en précisant qui est le locuteur lorsque c&#8217;était nécessaire. A vous de nous dire si vous appréciez le format <img src='http://blog.excilys.com/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' />  !</div>
<p>Une fois n&#8217;est pas coutume, ce deuxième mardi du mois a été l&#8217;occasion pour les Javaïstes parisiens d&#8217;assister au <a href="http://www.parisjug.org/">Paris JUG</a>, consacré cette fois aux processus de <em>build</em>, <em>share</em> et <em>deployment</em>. Pas de chance, la salle était déjà bien pleine quand je <em>(Bastien)</em> suis arrivé&#8230; vite, une chaise tout devant !</p>
<p>De mon côté <em>(Pierre-Yves)</em>, ayant posé ma tente devant la salle la veille au soir, j&#8217;ai eu accès aux premiers rangs. Allez, je vous livre un petit secret : pour avoir un placement correct au Paris Jug, il faut arriver à 19h <img src='http://blog.excilys.com/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' />  (ou être une <a href="http://jduchess.org/duchess-france/">JDuchess</a> <img src='http://blog.excilys.com/wp-includes/images/smilies/icon_razz.gif' alt=':-P' class='wp-smiley' /> ). Je <em>(Pierre-Yves)</em> vais donc vous parler des trois premières présentations, et je <em>(Bastien)</em> continuerai avec les deux dernières.</p>
<p><span id="more-1935"></span></p>
<h3><a href="http://www.w3.org"><img class="alignright size-medium wp-image-1948" title="W3C" src="http://blog.excilys.com/wp-content/uploads/2010/05/w3c_logo-300x145.png" alt="" width="300" height="145" /></a>Les secrets de fabrication du W3C</h3>
<h4>Par <em>Alexandre Bertails</em></h4>
<p>Qui connaît réellement le <a href="http://www.w3.org/">W3C</a> ? En dehors des outils de validation et des spécifications HTML 5, peu d&#8217;entre nous en savent plus sur cet acteur historique du Web. Alexandre Bertails nous en dit plus, dans un temps imparti relativement court.</p>
<p>Saviez-vous que le site web du W3C vient d&#8217;être refait à neuf, après <strong>un an et demi</strong> de travail ? Ce n&#8217;est pas juste une CSS, le contenu et l&#8217;arborescence ont été revus, <strong>sans cependant casser aucun lien</strong>. Allez-y, <a href="http://www.w3.org/">visitez-le</a> (bien plus joli qu&#8217;en <a href="http://web.archive.org/web/20080102062931/http://www.w3.org/">2008</a>, <a href="http://web.archive.org/web/20011217200741/www.w3.org/">2002</a> et même <a href="http://web.archive.org/web/19961227091242/http://www19.w3.org/">1996</a>).</p>
<p>J&#8217;ai aussi découvert que le W3C est composé à 40% de français. Que les outils avec lesquels travaillaient les salariés n&#8217;étaient pas forcément orientés Web, mais que les choses ont bien évolué récemment.</p>
<p>On regrettera le flux permanent des retardataires (ça va, je (<em>Bastien</em>) le saurai pour la prochaine fois !), qui ont quelque peu perturbé notre attention à tous, sans toutefois départir Alexandre de ses moyens (et c&#8217;est tout à son honneur !).</p>
<h3>DVCS</h3>
<h4>Par <em>Sébastien Douche</em></h4>
<p>Speaker hors pair, <a href="http://twitter.com/sdouche">Sébastien Douche</a> nous a donné envie de nous jeter à l&#8217;eau (pardon&#8230; facile celle-là) et de nous mettre immédiatement aux <a href="http://en.wikipedia.org/wiki/Distributed_Version_Control_System">DVCS</a> (Distributed Version Control System, système de gestion de versions distribué).</p>
<p>Auparavant, lorsqu&#8217;il intégrait un nouveau groupe de travail, Sébastien avait l&#8217;habitude d&#8217;y déployer sa boîte à outil habituelle : SVN, et <a href="http://trac.edgewall.org/">Trac</a>. Jusqu&#8217;au jour où il s&#8217;est retrouvé chef de projet sur un projet from scratch.</p>
<p style="text-align: center;"><img class="size-full wp-image-1953 aligncenter" title="Hors Piste" src="http://blog.excilys.com/wp-content/uploads/2010/05/hors_piste.jpg" alt="" width="341" height="454" /></p>
<p>J&#8217;aime beaucoup la métaphore qu&#8217;il nous a donné : la <strong>maintenance</strong> d&#8217;une application, c&#8217;est du <strong>ski sur pistes</strong>, il y a des dizaines de développeurs qui sont passés avant toi et qui ont tracé la piste. Le développement <strong>à partir de zéro</strong>, c&#8217;est du <strong>ski hors piste</strong>, tu sais la direction que tu veux prendre, mais tu es en haut de la montagne, ya du brouillard, il faut se lancer, et tu n&#8217;as pas de repères immédiats.</p>
<p>Avec le temps, le projet, pourtant &#8220;agile&#8221;, a eu de plus en plus de mal à livrer dans les temps, et la qualité de travail s&#8217;est progressivement dégradée. Pourquoi ? Parce que les développeurs passaient leur temps à faire des micro-commit/micro-merge et à intégrer le travail des autres, au lieu de pouvoir se consacrer au développement des fonctionnalités.</p>
<p>C&#8217;est une sale habitude que nous donne SVN : <strong>merger</strong> le code est vécu comme une <strong>expérience difficile</strong>. On préfère donc commiter le plus vite possible pour que ce soient les autres développeurs qui aient à merger. Les micro-commit sont aussi bien moins difficiles à merger. Quand aux branches SVN, elles sont aussi faciles à créer que complexes à merger&#8230;</p>
<p><strong>SVN</strong> ne sert plus au final qu&#8217;à faire de l&#8217;<strong>historisation</strong>, c&#8217;est un super &#8220;Annuler / Répéter&#8221;.</p>
<p>Les DVCS récents permettent à chaque développeur de travailler en local (fonctions d&#8217;historisation) et en isolation, et de pousser le code sur un repository central uniquement lorsque la fonctionnalité est terminée. Leur grande force est la flexibilité qu&#8217;ils introduisent, permettant à chacun de bosser comme il l&#8217;entend tout en respectant les règles d&#8217;organisation du groupe.</p>
<p>Il est aujourd&#8217;hui possible de passer à un DVCS en douceur, sur son poste de travail, en important un repository SVN qui peut rester le repository principal, mais en disposant des avantages d&#8217;un Git ou d&#8217;un Mercurial en local.</p>
<p><strong>Sébastien</strong> en a aussi profité pour nous présenter la manière dont travaille son équipe : le repository central comporte <strong>uniquement du code &#8220;livrable&#8221;</strong> (au sens livraison de fin de Sprint). Chaque fois qu&#8217;une <strong>fonctionnalité</strong> a été <strong>codée</strong> par un développeur, une <strong>revue de code</strong> est réalisée par un autre développeur, une <strong>démo</strong> est réalisée, et si tout va bien alors seulement les<strong> modifications </strong>sont<strong> poussées</strong> sur le repository central.</p>
<p>Sa <strong>conclusion</strong> : si vous ne devez apprendre qu&#8217;une techno en 2010, ce n&#8217;est pas <span style="text-decoration: line-through;">Scala</span>, <span style="text-decoration: line-through;">JEE 6</span>, <span style="text-decoration: line-through;">Maven 3</span>&#8230; <strong>apprenez à utiliser un DVCS</strong> !</p>
<h3>Git</h3>
<h4>Par <em>David Gageot</em></h4>
<p>Plutôt que de faire de sa présentation un énième tutoriel sur Git et tous les concepts associés, <a href="http://twitter.com/dgageot">David Gageot</a> a préféré nous montrer la puissance de Git en quelques exemple pratiques.</p>
<p>Tout d&#8217;abord, <code class="codecolorer bash default"><span class="bash"><span style="color: #c20cb9; font-weight: bold;">git</span> bisect</span></code>. Cette fonctionnalité permet d&#8217;automatiser la recherche du commit qui a créé une régression. Le fonctionnement est simple : on fournit à Git un script permettant de déterminer, pour une version donnée, si le bug est présent ou non. <code class="codecolorer bash default"><span class="bash"><span style="color: #c20cb9; font-weight: bold;">git</span> bisect</span></code> va ensuite réaliser une recherche <a href="http://fr.wikipedia.org/wiki/Dichotomie">dichotomique</a> entre deux numéros de versions, et identifier très rapidement le commit coupable.</p>
<p>Cette fonctionnalité n&#8217;a pas grand chose à voir avec le fait que Git soit un <strong>D</strong>VCS (distribué), mais reste un argument de poids pour adopter cet outil. C&#8217;est aussi possible grâce à la rapidité avec laquelle un Git ou un Mercurial peuvent réaliser un checkout ou changer de version sur une copie locale.</p>
<p>David nous a ensuite montré un script qu&#8217;il a réalisé, qui permet de conditionner automatiquement le push vers le repository au fait que le build et les tests passent. Il peut donc tranquillement bosser et commiter pendant qu&#8217;en tâche de fond le build et les tests sont exécutés, et ainsi se passer d&#8217;un <a href="http://blog.excilys.com/2010/04/21/hudson-retour-dexperience-et-conseils-pratiques/">Hudson</a>.</p>
<p>La présentation s&#8217;est terminée par des démonstration sur l&#8217;évolution de dépôts Git à l&#8217;aide de <a href="http://code.google.com/p/gource/">Gource</a>, qui permet de représenter dans le temps les modifications effectuées sur un dépôt de sources, et le travail de chacun.</p>
<div id="attachment_1965" class="wp-caption aligncenter" style="width: 490px"><a href="http://code.google.com/p/gource/wiki/Screenshots"><img class="size-full wp-image-1965" title="Le Gource du projet Linux" src="http://blog.excilys.com/wp-content/uploads/2010/05/gource-linux-small.jpg" alt="" width="480" height="360" /></a><p class="wp-caption-text">Le Gource du projet Linux</p></div>
<p>En conclusion, quelques conseils :</p>
<ul>
<li>testez Git le plus vite possible,</li>
<li>n&#8217;essayez pas de faire du SVN avec Git, il faut oublier comment SVN fonctionne, désapprendre les mauvais réflexes,</li>
<li>un bon moyen pour démarrer, c&#8217;est de jouer avec <a href="http://github.com/">github</a>,</li>
<li>n&#8217;hésitez pas à utiliser Git dans le cadre de vos projets, au moins en local, il vous apportera une forte plus value même si votre équipe continue d&#8217;utiliser SVN.</li>
</ul>
<h3>Pause Buffet</h3>
<p>Le buffet était gracieusement offert par <a href="http://twitter.com/nmartignole">Nicolas Martignole</a>, suite à <a href="http://www.touilleur-express.fr/2010/05/07/lexpress-board-offre-le-buffet-au-paris-jug-mardi-11-mai/">un défi</a> lancé sur Twitter. Il en a profité pour faire de la pub pour l&#8217;<a href="http://www.express-board.fr/">eXpress Board</a>, un job board pour les passionés. J&#8217;ai <em>(Pierre-Yves)</em> aussi pu croiser <a href="http://twitter.com/emmanuelbernard">Emmanuel Bernard</a>, apprenant ainsi que si l&#8217;équipe Hibernate n&#8217;utilise pas de DVCS pour le moment, ils songent à y passer, notamment pour faciliter l&#8217;intégration de contributions externes.</p>
<h3>Build it with Maven 3!</h3>
<h4>Par <em>Nicolas de Loof</em> &amp; <em>Arnaud Héritier</em></h4>
<p>Invités surprise, <a href="http://twitter.com/ndeloof">Fred</a> et <a href="http://twitter.com/aheritier">Jamy</a> nous ont montré que Maven, c&#8217;est pas sorcier ! Certains se souviennent encore des migrations longues et périlleuses des Makefile vers Ant, puis vers Maven 1 et Maven 2. Cette fois, les développeurs du célèbre gestionnaire de build ont voulu éviter cela : la compatibilité de Maven 3 avec des projets en version 2 est en théorie de 99.99% (hormis maven site qui n&#8217;est pas encore au point).</p>
<div id="attachment_1970" class="wp-caption alignleft" style="width: 360px"><a href="http://oreilly.com/catalog/9780596517335"><img class="size-full wp-image-1970" title="Maven 3" src="http://blog.excilys.com/wp-content/uploads/2010/05/maven3.jpg" alt="" width="350" height="256" /></a><p class="wp-caption-text">Première rencontre avec Maven 3</p></div>
<p>Les mots-clé de la première release stable seront donc les suivants :</p>
<ul>
<li><strong>compatibilité</strong> : en prenant n&#8217;importe quel projet Maven 2, sans aucune modification on pourra le builder avec Maven 3,</li>
<li><strong>modularité/extensibilité</strong> : le socle de l&#8217;application a été entièrement repensé (en évitant les problèmes de rigidité et de complexité de la version 2). Au menu, utilisation de Java 5, apparition d&#8217;APIs simples et intuitives, de la doc&#8230; Bref, de quoi faire des plugins sans se prendre la tête,</li>
<li><strong><a href="http://maven.apache.org/mercury/index.html">Mercury</a></strong> : ce système voué à remplacer le mécanisme d&#8217;artifacts&#8230; a finalement été abandonné <img src='http://blog.excilys.com/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' /> .</li>
</ul>
<p>Maven 3 introduit la notion de <strong><em>build plan</em><span style="font-weight: normal;">, qui permet de savoir à l&#8217;avance toutes les actions qui vont être effectuées dans un build (une sorte de contexte d&#8217;exécution). Ainsi, un plugin sera au courant de ce que feront les autres, donnant la possibilité d&#8217;avoir des builds intelligents (où les tests ne seront pas lancés deux fois par deux plugins différents par exemple).</span></strong></p>
<p><strong><span style="font-weight: normal;">Au niveau des descripteurs de build, la structure des pom.xml a été améliorée et Maven 3 devient polyglotte. On peut à présent écrire des descripteurs en <a href="http://www.wakaleo.com/blog/236-writing-your-pom-files-in-groovy-a-sneek-preview-of-maven-3s-polyglot-features">groovy</a> ou en python par exemple. Les exclusions globales de dépendances sont maintenant possibles (on va enfin pouvoir se débarrasser de cette *$#~ de dépendance sur un logger qui plante toujours&#8230; <img src='http://blog.excilys.com/wp-includes/images/smilies/icon_razz.gif' alt=':-P' class='wp-smiley' /> ). </span></strong></p>
<p><strong><span style="font-weight: normal;">Toujours dans les descripteurs, la notion de </span><span style="font-weight: normal;"><em>mixins</em><span style="font-weight: normal;"> est apparue :</span></span></strong></p>
<blockquote><p><strong><span style="font-weight: normal;"><span style="font-weight: normal;">Essentially it will be a POM consisting of plugins and configurations that can be externally parameterized. These mixins will be deployed to a repository and be referenced with a standard coordinate. Basically it will be an intelligent import with validation which will allow composition in your POMs.</span></span></strong></p></blockquote>
<p>On va pouvoir décomposer notre POM en différents morceaux, un peu à la manière des <a href="http://blogs.sun.com/swchan/entry/servlet_3_0_web_fragment">web-fragments</a>.</p>
<p><strong><span style="font-weight: normal;"><span style="font-weight: normal;">Les </span>builds parallèles<span style="font-weight: normal;"> vont bientôt faire leur apparition, pour ne pas que vos 7 autres cores s&#8217;ennuient <em>(edit: Mathieu nous signale en commentaire que les builds parallèles sont déjà disponibles depuis la version 3.0-beta-1)</em>. Cette fonctionnalité sera très intéressante sur les serveurs d&#8217;intégration continue utilisant un modèle maitre/esclave (<a href="http://blog.excilys.com/2010/04/21/hudson-retour-dexperience-et-conseils-pratiques/">Hudson</a>, pour ne citer que lui). Techniquement, le processus de build sera découpé en différentes phases qui se rejoindront en des points de synchronisation.</span></span></strong></p>
<p>Mais au final, qu&#8217;apporte Maven 3 par rapport à Maven 2 à l&#8217;heure actuelle ? Rien, enfin presque :</p>
<ul>
<li>un shell (avec des jolies couleurs !) permet de faciliter les builds (notamment sous Windows),</li>
<li>un gain de rapidité lors des builds.</li>
</ul>
<p>Comme la migration de M2 vers M3 est très simple et rapide, nos deux speakers encouragent vivement les développeurs à tester Maven 3 chez eux, ne serait-ce que pour les gains en terme de rapidité de build. A vos pom, donc !</p>
<h3>Deploy it with&#8230; DeployIt!</h3>
<h4>Par <em>Guillaume Bodet</em> &amp; <em>Benoit Moussaud</em></h4>
<p><img class="alignright size-full wp-image-1963" title="DeployIt" src="http://blog.excilys.com/wp-content/uploads/2010/05/deployit-logo-small.png" alt="" width="206" height="36" /><a href="http://blog.xebia.fr/author/gbodet/">Guillaume</a> et <a href="http://www.twitter.com/bmoussaud">Benoit</a> nous ont présenté les fondamentaux du bébé développé par XebiaLabs, <strong><a href="http://www.xebialabs.com/deployit-automated-deployment-java-applications">DeployIt</a></strong>. Cet outil part du constat qu&#8217;un déploiement ne consiste pas en une simple copie d&#8217;EAR/WAR. Il y a généralement d&#8217;autres éléments à configurer (DataSources, JMS), des scripts SQL à lancer, des batches à mettre en place, etc.</p>
<p>DeployIt permet de gérer toutes ces étapes de manière intelligente et de faciliter l&#8217;installation d&#8217;une application. Il est repose sur <a href="http://www.xebialabs.com/architecture">trois briques principales</a> :</p>
<ul>
<li>le cœur,</li>
<li>des interfaces (Flex, console, Maven, Eclipse, dashboards&#8230;),</li>
<li>des plugins permettant le support de JBoss, Apache, .NET etc.</li>
</ul>
<p>La préparation d&#8217;une installation se fait en deux étapes. Dans un premier temps, on configure le <em>Configuration Item Repository</em> (CIR), qui est un référentiel d&#8217;informations sur les différents environnements de déploiement (test, performances, etc.). Ensuite, l&#8217;ensemble des opérations à effectuer est décrite dans des <em>runbooks</em> : déploiement d&#8217;un EAR, configuration d&#8217;une DataSource, installation d&#8217;un script SQL&#8230;</p>
<p>A partir de ces deux sources d&#8217;information, l&#8217;<em>Intelligent Runbook Resolution Engine</em> va se charger d&#8217;interroger les différents runbooks pour constituer un scénario de déploiement, en se basant sur les caractéristiques de l&#8217;environnement décrites dans le CIR.</p>
<p>Un des aspects intéressants dans DeployIt est sa faible intrusion :</p>
<ul>
<li>Il est <em>agent-less</em>, et va utiliser les moyens existants tels que ssh, sftp, scp.</li>
<li>Il utilise les interfaces natives lorsqu&#8217;elles sont disponibles (wsadmin, JDBC&#8230;).</li>
<li>Un plugin Maven permet de lancer les déploiements au sein d&#8217;un processus de build (au sens Maven) déjà existant dans le projet.</li>
</ul>
<p>Seul bémol : DeployIt est un outil commercial, il existe une <a href="http://www.xebialabs.com/deployit-personal-edition-request">version gratuite</a> mais qui n&#8217;intègre aucune notion de sécurité&#8230; XebiaLabs a ainsi la volonté de permettre aux gens de tester ce produit chez eux, tout en empêchant la possibilité de l&#8217;utiliser pour faire de vrais déploiements en production (sauf si vous êtes kamikaze).</p>
<p>Cependant, XebiaLabs songe à relâcher son outil en Open-Source. La majorité absolue des personnes présentes dans la salle a d&#8217;ailleurs voté positivement pour une telle action, en réponse à un sondage improvisé d&#8217;<a href="http://www.parisjug.org/xwiki/bin/view/Speaker/GoncalvesAntonio">Antonio</a> <img src='http://blog.excilys.com/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' /> .</p>
<h3>Conclusion</h3>
<p>Ce Paris JUG fût riche en enseignements et en conférences de qualité. D&#8217;autres compte rendus ont été publiés sur le web : sur le blog du <a href="http://www.touilleur-express.fr/2010/05/12/la-soiree-du-11-mai-2010-au-paris-jug-git-dvcs-et-lexpress-board/">Touilleur Express</a>, et sur le blog des <a href="http://jduchess.org/duchess-france/paris-jug-de-mai-build-share-deploy-jusquau-bout-de-la-nuit-1/">JDuchess</a>.</p>
<p>Le prochain Paris JUG aura lieu le 8 juin, avec une invitée à l&#8217;honneur : <a href="http://www.parisjug.org/xwiki/bin/view/Meeting/20100608">Holly Cummins</a>.</p>
<img src="http://feeds.feedburner.com/~r/blogexcilyscom/~4/9W2x5lyQDLc" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.excilys.com/2010/05/14/compte-rendu-du-paris-jug-soiree-build-share-deploy/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		<feedburner:origLink>http://blog.excilys.com/2010/05/14/compte-rendu-du-paris-jug-soiree-build-share-deploy/</feedburner:origLink></item>
		<item>
		<title>CAS et Grails, sans sarCASmes !</title>
		<link>http://feedproxy.google.com/~r/blogexcilyscom/~3/l5Z-CtnJr8k/</link>
		<comments>http://blog.excilys.com/2010/05/06/cas-et-grails-sans-sarcasmes/#comments</comments>
		<pubDate>Thu, 06 May 2010 13:04:31 +0000</pubDate>
		<dc:creator>Pierre-Yves RICAU</dc:creator>
				<category><![CDATA[Non classé]]></category>
		<category><![CDATA[cas]]></category>
		<category><![CDATA[grails]]></category>
		<category><![CDATA[groovy]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[single sign-on]]></category>
		<category><![CDATA[single sign-out]]></category>
		<category><![CDATA[sso]]></category>
		<category><![CDATA[tutoriel]]></category>

		<guid isPermaLink="false">http://blog.excilys.com/?p=1512</guid>
		<description><![CDATA[
Propos liminaire
Cet article traite de la cassification d&#8217;une application Grails. Ce néologisme pas très catholique, plus souvent employé dans la langue Shakespearienne, est synonyme d&#8217;intégration d&#8217;une application avec le système d&#8217;authentification centralisée Open Source le plus stylé au monde, j&#8217;ai nommé : CAS.

CAS, mais pourquoi faire ?
Nota : si vous connaissez déjà bien CAS et [...]]]></description>
			<content:encoded><![CDATA[<p><img class="size-full wp-image-622  alignright" title="Grails" src="http://blog.excilys.com/wp-content/uploads/2009/12/grailslogo_topNav.png" alt="Grails.org" width="163" height="43" /><img class="alignright size-full wp-image-1903" title="CAS" src="http://blog.excilys.com/wp-content/uploads/2010/05/casLogo.jpg" alt="CAS" width="124" height="66" /></p>
<h3>Propos liminaire</h3>
<p>Cet article traite de la cassification d&#8217;une application Grails. Ce néologisme pas très catholique, plus souvent employé dans la langue <a href="http://tinyurl.com/y8njxwg">Shakespearienne</a>, est synonyme d&#8217;intégration d&#8217;une application avec le système d&#8217;authentification centralisée Open Source <strong>le plus stylé au monde</strong>, j&#8217;ai nommé : <a href="http://www.jasig.org/cas">CAS</a>.</p>
<p><span id="more-1512"></span></p>
<h3>CAS, mais pourquoi faire ?</h3>
<p>Nota : si vous connaissez déjà bien CAS et que seule l&#8217;intégration avec Grails vous intéresse, vous pouvez passer à la partie suivante, je ne vous en voudrai pas <img src='http://blog.excilys.com/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' />  .</p>
<p>CAS est un système d&#8217;authentification qui permet d&#8217;<strong>authentifier </strong>des <strong>utilisateurs </strong>de manière sécurisée. La quasi-totalité des applications d&#8217;un système d&#8217;information nécessitent une authentification des utilisateurs.</p>
<p>Sans système d&#8217;authentification centralisé, chaque application se retrouve à développer ses propres pages de login, et gère l&#8217;authentification à sa sauce. Pour éviter d&#8217;avoir à créer/gérer / stocker les informations d&#8217;authentification dans chacune des applications, la solution consiste bien souvent à créer un référentiel commun, par exemple un LDAP, un Active Directory, ou encore une base de données commune.</p>
<p>Cette approche est alléchante, mais présente plusieurs problèmes :</p>
<ul>
<li>les développements ne sont pas factorisés, il faut redévelopper les pages de login / la mécanique d&#8217;accès au référentiel commun pour chaque webapp,</li>
<li>la mécanique d&#8217;authentification n&#8217;est pas unifiée, les designs sont différents, et les utilisateurs peuvent être rapidement perdus,</li>
<li>la <strong>sécurité de l&#8217;ensemble du SI</strong> repose sur la <strong>sécurité de chacune des webapp</strong>. Chaque webapp a potentiellement accès aux informations d&#8217;authentification de tous les utilisateurs. Il suffit d&#8217;une faille à un endroit pour que <strong>tout le système soit compromis</strong>.</li>
<li>Les utilisateurs doivent s&#8217;authentifier sur chacune des applications web.</li>
<li>De même, ils doivent se déconnecter manuellement sur chacune des applications.</li>
</ul>
<p>CAS répond parfaitement à ces problématiques :</p>
<ul>
<li>Lorsqu&#8217;ils doivent s&#8217;authentifier sur une application, les utilisateurs sont automatiquement redirigés vers CAS. Il n&#8217;y a donc un seul point d&#8217;entrée pour l&#8217;authentification.</li>
<li>Les utilisateurs ne sont pas perdus, ils reconnaissent la page de login CAS, et savent aussi immédiatement identifier s&#8217;ils sont sur la &#8220;vraie&#8221; page d&#8217;authentification étant donné que l&#8217;url est unique (moins de risques de phishing).</li>
<li><strong>Seul CAS</strong> a accès aux <strong>informations d&#8217;authentification</strong>. De part son caractère Open Source, sa maturité, et sa large adoption, CAS est nettement moins exposé à de potentielles failles de sécurité que vos applications développées en interne. Oui, <strong>vos applications contiennent des failles de sécurité</strong>. De part la nature du développement logiciel et sa complexité, il n&#8217;y a aucune raison pour que vous soyez mystérieusement épargné.</li>
<li>CAS bénéficie d&#8217;un fort soutient de la communauté, et s&#8217;intègre avec de <a href="http://www.jasig.org/cas/client-integration">très nombreuses solutions</a>. Il y a de fortes chances pour que les développements pour intégrer CAS à vos webapps soient réduits au minimum. Les nombreuses possibilités d&#8217;intégration de CAS peuvent être résumées par cette simple citation littéraire :<br />
<blockquote><p>Tu pars du Nord Ouest pour arriver au Sud Est, sans toucher la Corse ! Et tu CAS, et tu CAS !</p></blockquote>
</li>
<li>CAS<strong> </strong>permet d&#8217;activer le <strong>SSO</strong> (Single Sign-On, aka <a href="http://fr.wikipedia.org/wiki/Authentification_unique">Authentification Unique</a>) : l&#8217;utilisateur s&#8217;authentifie une fois, puis peut avoir accès à l&#8217;ensemble des applications du SI sans jamais rentrer de nouveaux ses informations d&#8217;authentification.</li>
<li>Mieux, <strong>CAS gère le Single Sign-Out</strong>. Il est ainsi possible pour un utilisateur de se déconnecter de l&#8217;ensemble des applications en une seule action.</li>
<li>Enfin, CAS permet aussi la délégation d&#8217;authentification, par exemple pour permettre à une application d&#8217;utiliser votre identité pour contacter les web services d&#8217;une autre application. Je n&#8217;en parlerai pas dans cet article, mais peut-être ultérieurement, c&#8217;est un sujet passionnant.</li>
</ul>
<h3>Ya quoi sous la carCASse ?</h3>
<p style="text-align: center;"><img class="size-full wp-image-1915 aligncenter" title="carCASse" src="http://blog.excilys.com/wp-content/uploads/2010/05/carcasse.jpg" alt="carcasse" width="400" height="300" /></p>
<p>Sans trop entrer dans les détails du <a href="http://www.jasig.org/cas/protocol">protocole CAS</a>, en voici les principes généraux :</p>
<ul>
<li>Lorsque l&#8217;utilisateur s&#8217;authentifie auprès de CAS, il <strong>obtient un TGT </strong>(Ticket Granting Ticket). Ce ticket n&#8217;est jamais présenté aux applications, il permet à CAS d&#8217;identifier l&#8217;utilisateur.</li>
<li>Lorsque l&#8217;utilisateur souhaite utiliser un service (une application), il <strong>demande à CAS un ST </strong>(Service Ticket) pour le service donné, <strong>en fournissant son TGT</strong> ainsi que le nom du service.</li>
<li>L&#8217;utilisateur <strong>présente ensuite son ST</strong> à l&#8217;application. Celle-ci contacte CAS en lui fournissant le ST et son nom de service. <strong>CAS retourne l&#8217;identité de l&#8217;utilisateur</strong>.</li>
<li>Dès lors, l&#8217;application peut placer l&#8217;identité de l&#8217;utilisateur dans la session qu&#8217;elle maintient avec celui-ci.</li>
<li>Afin d&#8217;être compatible avec une utilisation web, ce protocole se traduit en pratique par un <strong>stockage du TGT dans un cookie</strong> accessible uniquement à CAS, et l&#8217;utilisation de <strong>redirections HTTP</strong> avec des URL du type &#8220;/cas/login?service=nomService&#8221; pour demander un ST et &#8220;/myapp/login?ST=leTicket&#8221; pour authentifier l&#8217;utilisateur au sein d&#8217;une application.</li>
</ul>
<p>Notez qu&#8217;on trouve des ressemblances avec le protocole <a href="http://fr.wikipedia.org/wiki/Kerberos">Kerberos</a>, à ceci prêt que les tickets ne contiennent pas directement l&#8217;identité de l&#8217;utilisateur.</p>
<h4>Et le Single Sign-out ?</h4>
<ul>
<li>En pratique, le nom du service est l&#8217;URL vers laquelle l&#8217;utilisateur va être redirigé une fois que CAS a généré un ST. CAS maintient en mémoire la liste des URL pour lesquelles l&#8217;utilisateur a demandé un ST.</li>
<li>Lorsque l&#8217;utilisateur demande à se déconnecter, CAS envoie une requête POST d&#8217;un <a href="http://www.ja-sig.org/wiki/display/CASUM/Single+Sign+Out">format particulier</a> à chacune de ces URL. Charge ensuite à chaque application de supprimer la session correspondante.</li>
<li>En JEE, cela se traduit par la <a href="http://www.ja-sig.org/wiki/display/CASC/Configuring+Single+Sign+Out">mise en place</a> d&#8217;un servlet filter et d&#8217;un listener spécifiques sur chaque application.</li>
</ul>
<h3>Installer CAS sans être CASse-cou</h3>
<p>Avant toute chose, <strong>il nous faut un CAS</strong>. On pourrait se créer un WAR aux petits oignons, <a href="http://www.ja-sig.org/wiki/display/CASUM/Best+Practice+-+Setting+Up+CAS+Locally+using+the+Maven2+WAR+Overlay+Method">en suivant cette procédure</a>. Poil dans la main oblige, on va plutôt le télécharger directement : <a href="http://oss.sonatype.org/content/repositories/releases/org/jasig/cas/cas-server-webapp/3.4.2/cas-server-webapp-3.4.2.war">cas-server-webapp-3.4.2.war</a>. Cette version de CAS a une petite particularité : pour se connecter, il suffit d&#8217;entrer un mot de passe identique au login, quelque soit le login.</p>
<p>Déployez le WAR dans un Tomcat, et testez : <a href="http://localhost:8181/cas-server-webapp-3.4.2/login">http://localhost:8181/cas-server-webapp-3.4.2/login</a>. Pourquoi le port 8181 ? Parce qu&#8217;on va réserver le 8080 pour le jetty lancé par Grails <img src='http://blog.excilys.com/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' />  .</p>
<div id="attachment_1898" class="wp-caption aligncenter" style="width: 514px"><img class="size-full wp-image-1898 " title="Login sur CAS" src="http://blog.excilys.com/wp-content/uploads/2010/05/cas_piwai_ptit.png" alt="Login sur CAS" width="504" height="449" /><p class="wp-caption-text">Login sur CAS</p></div>
<p>Notez que le Single Sign-On ne sera disponible qu&#8217;à la condition que <strong>vous configuriez le SSL</strong>.</p>
<h3>CAS toi, pauvre Con..tact !</h3>
<p>Je vous propose maintenant de CASsifier une application Grails existante : <strong>ZenContact</strong>, présentée au cours d&#8217;un <a href="http://blog.excilys.com/2010/02/08/android-pour-lentreprise-5-zencontact-json-relax-avec-gson/">article précédent</a>.</p>
<p>Vous n&#8217;êtes pas sans savoir que Grails, c&#8217;est du <a href="http://www.grails.org/doc/1.1/guide/14.%20Grails%20and%20Spring.html">Spring  MVC déguisé</a> (vous aussi, créez votre framework web <a href="http://blog.zenika.com/index.php?post/2010/04/26/Building-a-web-framework-on-top-of-Spring-MVC">au  dessus de Spring MVC</a>). On peut donc utiliser Spring Security, qui s&#8217;intègre bien avec CAS.</p>
<p>Et ça tombe bien, il existe un plugin Grails qui va nous simplifier le travail : le <a href="http://grails.org/plugin/acegi">Spring Security Plugin</a>. Le blog Xebia en a d&#8217;ailleurs parlé dans un <a href="http://blog.xebia.fr/2010/02/25/grails-spring-security-plugin-la-securite-facile/">article plutôt complet</a>.</p>
<p>Installez le plugin Acegi :</p>
<pre>
<div class="codecolorer-container bash default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">grails install-plugin acegi</div></td></tr></tbody></table></div>
</pre>
<p>Créez les entités pour la sécurité (utilisateurs, rôles, et mapping des url sécurisées) :</p>
<pre>
<div class="codecolorer-container bash default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br /></div></td><td><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">grails create-auth-domains<br />
&nbsp; &nbsp;com.excilys.blog.zencontact.User<br />
&nbsp; &nbsp;com.excilys.blog.zencontact.Role<br />
&nbsp; &nbsp;com.excilys.blog.zencontact.RequestMap</div></td></tr></tbody></table></div>
</pre>
<p>Je vous propose de créer les utilisateurs, les rôles et les urls protégées dans la base de données mémoire au démarrage de l&#8217;application. Il suffit de modifier le fichier <code class="codecolorer bash default"><span class="bash"><span style="color: #007800;">$PROJECT_HOME</span><span style="color: #000000; font-weight: bold;">/</span>grails-app<span style="color: #000000; font-weight: bold;">/</span>conf<span style="color: #000000; font-weight: bold;">/</span>BootStrap.groovy</span></code> et d&#8217;y ajouter le snippet suivant :</p>
<pre>
<div class="codecolorer-container groovy default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;height:300px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br /></div></td><td><div class="groovy codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #a1a100;">com.excilys.blog.zencontact.User</span><br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #a1a100;">com.excilys.blog.zencontact.Role</span><br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #a1a100;">com.excilys.blog.zencontact.RequestMap</span><br />
<br />
<span style="color: #808080; font-style: italic;">// [...]</span><br />
<br />
<span style="color: #000000; font-weight: bold;">def</span> roleUser <span style="color: #66cc66;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Role<span style="color: #66cc66;">&#40;</span>authority: <span style="color: #ff0000;">'ROLE_USER'</span>, description: <span style="color: #ff0000;">'Utilisateur'</span><span style="color: #66cc66;">&#41;</span><br />
roleUser.<span style="color: #006600;">save</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><br />
<br />
<span style="color: #000000; font-weight: bold;">def</span> roleContact <span style="color: #66cc66;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Role<span style="color: #66cc66;">&#40;</span>authority: <span style="color: #ff0000;">'ROLE_CONTACT'</span>, description: <span style="color: #ff0000;">'Accès aux contacts'</span><span style="color: #66cc66;">&#41;</span><br />
roleContact.<span style="color: #006600;">save</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><br />
<br />
<span style="color: #000000; font-weight: bold;">def</span> user1 <span style="color: #66cc66;">=</span> <span style="color: #000000; font-weight: bold;">new</span> User<span style="color: #66cc66;">&#40;</span>username: <span style="color: #ff0000;">'piwai'</span>, passwd:<span style="color: #ff0000;">'NOT_USED'</span>, userRealName: <span style="color: #ff0000;">'Piwaï'</span>,<br />
&nbsp; &nbsp; enabled: <span style="color: #000000; font-weight: bold;">true</span>, email: <span style="color: #ff0000;">'ano@nymous.com'</span><span style="color: #66cc66;">&#41;</span><br />
user1.<span style="color: #006600;">addToAuthorities</span><span style="color: #66cc66;">&#40;</span>roleUser<span style="color: #66cc66;">&#41;</span><br />
user1.<span style="color: #006600;">addToAuthorities</span><span style="color: #66cc66;">&#40;</span>roleContact<span style="color: #66cc66;">&#41;</span><br />
user1.<span style="color: #006600;">save</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><br />
<br />
<span style="color: #000000; font-weight: bold;">def</span> user2 <span style="color: #66cc66;">=</span> <span style="color: #000000; font-weight: bold;">new</span> User<span style="color: #66cc66;">&#40;</span>username: <span style="color: #ff0000;">'pyricau'</span>, passwd:<span style="color: #ff0000;">'NOT_USED'</span>, userRealName: <span style="color: #ff0000;">'Pierre-Yves Ricau'</span>,<br />
&nbsp; &nbsp; enabled: <span style="color: #000000; font-weight: bold;">true</span>, email: <span style="color: #ff0000;">'ano@nymous.com'</span><span style="color: #66cc66;">&#41;</span><br />
<br />
user2.<span style="color: #006600;">addToAuthorities</span><span style="color: #66cc66;">&#40;</span>roleUser<span style="color: #66cc66;">&#41;</span><br />
user2.<span style="color: #006600;">save</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><br />
<br />
<span style="color: #000000; font-weight: bold;">new</span> RequestMap<span style="color: #66cc66;">&#40;</span>url: <span style="color: #ff0000;">'/contact/**'</span>, configAttribute: <span style="color: #ff0000;">'ROLE_CONTACT'</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">save</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span></div></td></tr></tbody></table></div>
</pre>
<p>Passons aux choses sérieuses, la configuration du plugin pour utiliser CAS. Modifiez le fichier <code class="codecolorer bash default"><span class="bash"><span style="color: #007800;">$PROJECT_HOME</span><span style="color: #000000; font-weight: bold;">/</span>grails-app<span style="color: #000000; font-weight: bold;">/</span>conf<span style="color: #000000; font-weight: bold;">/</span>SecurityConfig.groovy</span></code>, et ajoutez-y la conf suivante :</p>
<pre>
<div class="codecolorer-container groovy default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td><div class="groovy codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">useCAS <span style="color: #66cc66;">=</span> <span style="color: #000000; font-weight: bold;">true</span><br />
cas.<span style="color: #006600;">localhostSecure</span> <span style="color: #66cc66;">=</span> <span style="color: #000000; font-weight: bold;">false</span><br />
cas.<span style="color: #006600;">fullServiceURL</span> <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">'http://localhost:8181/cas-server-webapp-3.4.2'</span><br />
cas.<span style="color: #006600;">fullLoginURL</span> <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">&quot;$cas.fullServiceURL/login&quot;</span><br />
cas.<span style="color: #006600;">failureURL</span> <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">'/login/denied'</span><br />
afterLogoutUrl <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">'/logout/afterLogout'</span></div></td></tr></tbody></table></div>
</pre>
<p>Et oui, c&#8217;est aussi simple que cela ! La propriété <strong>afterLogoutUrl</strong> indique la page à afficher une fois que l&#8217;utilisateur s&#8217;est déconnecté. Il faut donc créer l&#8217;action correspondante dans le LogoutController (<code class="codecolorer bash default"><span class="bash"><span style="color: #007800;">$PROJECT_HOME</span><span style="color: #000000; font-weight: bold;">/</span>grails-app<span style="color: #000000; font-weight: bold;">/</span>controllers<span style="color: #000000; font-weight: bold;">/</span>LogoutController.groovy</span></code>) :</p>
<pre>
<div class="codecolorer-container groovy default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;height:300px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br /></div></td><td><div class="groovy codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">class</span> LogoutController <span style="color: #66cc66;">&#123;</span><br />
<br />
&nbsp; <span style="color: #000000; font-weight: bold;">def</span> authenticateService<span style="color: #66cc66;">;</span><br />
<br />
&nbsp; <span style="color: #808080; font-style: italic;">/**<br />
&nbsp; &nbsp;* Index action. Redirects to the Spring security logout uri.<br />
&nbsp; &nbsp;*/</span><br />
&nbsp; <span style="color: #000000; font-weight: bold;">def</span> index <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#123;</span><br />
&nbsp; &nbsp; redirect<span style="color: #66cc66;">&#40;</span>uri: <span style="color: #ff0000;">'/j_spring_security_logout'</span><span style="color: #66cc66;">&#41;</span><br />
&nbsp; <span style="color: #66cc66;">&#125;</span><br />
<br />
&nbsp; <span style="color: #000000; font-weight: bold;">def</span> afterLogout <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">def</span> backFromCasLogoutUrl <span style="color: #66cc66;">=</span> grailsApplication.<span style="color: #006600;">config</span>.<span style="color: #006600;">grails</span>.<span style="color: #006600;">serverURL</span><br />
<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">def</span> conf <span style="color: #66cc66;">=</span> authenticateService.<span style="color: #006600;">securityConfig</span>.<span style="color: #006600;">security</span><br />
<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">def</span> casLogoutUrl <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">&quot;$conf.cas.fullServiceURL/logout?url=$backFromCasLogoutUrl&quot;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #66cc66;">&#91;</span>casLogoutUrl:casLogoutUrl<span style="color: #66cc66;">&#93;</span><br />
&nbsp; <span style="color: #66cc66;">&#125;</span><br />
<span style="color: #66cc66;">&#125;</span></div></td></tr></tbody></table></div>
</pre>
<p>Ainsi que la vue associée (<code class="codecolorer bash default"><span class="bash"><span style="color: #007800;">$PROJECT_HOME</span><span style="color: #000000; font-weight: bold;">/</span>grails-app<span style="color: #000000; font-weight: bold;">/</span>view<span style="color: #000000; font-weight: bold;">/</span>logout<span style="color: #000000; font-weight: bold;">/</span>afterLogout.gsp</span></code>) :</p>
<pre>
<div class="codecolorer-container html4strict default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td><div class="html4strict codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">meta</span> <span style="color: #000066;">name</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">'layout'</span> <span style="color: #000066;">content</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">'main'</span> <span style="color: #66cc66;">/</span>&gt;</span><br />
<span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">title</span>&gt;</span>Déconnexion<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">title</span>&gt;</span><br />
<span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">'body'</span>&gt;</span><br />
Vous êtes désormais déconnecté de Zencontact.<span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">br</span> <span style="color: #66cc66;">/</span>&gt;</span><br />
Pour vous déconnecter du système d'authentification central, <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">a</span> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;${casLogoutUrl}&quot;</span> &gt;</span>cliquez ici<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">a</span>&gt;</span>.<br />
<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">div</span>&gt;</span></div></td></tr></tbody></table></div>
</pre>
<div id="attachment_1902" class="wp-caption aligncenter" style="width: 604px"><img class="size-full wp-image-1902 " title="Logout de ZenContact" src="http://blog.excilys.com/wp-content/uploads/2010/05/grails_logout.png" alt="Logout de ZenContact" width="594" height="168" /><p class="wp-caption-text">Logout de ZenContact</p></div>
<p>Il ne reste plus qu&#8217;à exécuter l&#8217;application (<code class="codecolorer bash default"><span class="bash">grails run-app</span></code>), puis accéder à <a href="http://localhost:8080/zencontactdemo/contact/list">une page sécurisée</a>. Et vous pouvez même <a href="http://localhost:8080/zencontactdemo/logout/index">vous déconnecter</a> ! Pour en savoir plus, consultez la configuration du <a href="http://www.grails.org/AcegiSecurity+Plugin+-+Customizing+with+SecurityConfig">plugin Spring Security</a>.</p>
<h3>Bonux : Single Sign-Out sans se décarCASser</h3>
<p>Et pour terminer en beauté, on aimerait être automatiquement déconnecté de ZenContact quand on se déconnecte de CAS. C&#8217;est très pratique pour se déconnecter instantanément de toutes les applications du système d&#8217;information.</p>
<p>En pratique, il s&#8217;agit simplement de modifier le <strong>web.xml</strong> pour y ajouter les <a href="http://www.ja-sig.org/wiki/display/CASC/Configuring+Single+Sign+Out">listeners et servlet filters</a> et qui vont bien. Cependant, vous aurez beau chercher, vous ne trouverez pas de <strong>web.xml</strong> dans les sources de votre application. Diantre, <strong>il est généré</strong> !</p>
<p>La technique la plus simple est encore de modifier le template qui sert à générer le web.xml, en exécutant <code class="codecolorer bash default"><span class="bash">grails install-templates</span></code> et en modifiant le fichier <code class="codecolorer bash default"><span class="bash"><span style="color: #007800;">$PROJECT_HOME</span><span style="color: #000000; font-weight: bold;">/</span>src<span style="color: #000000; font-weight: bold;">/</span>templates<span style="color: #000000; font-weight: bold;">/</span>war<span style="color: #000000; font-weight: bold;">/</span>web.xml</span></code> :</p>
<pre>
<div class="codecolorer-container xml default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br /></div></td><td><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;filter<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;filter-name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>signOutFilter<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/filter-name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;filter-class<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>org.jasig.cas.client.session.SingleSignOutFilter<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/filter-class<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/filter<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<span style="color: #808080; font-style: italic;">&lt;!-- ... --&gt;</span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;filter-mapping<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;filter-name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>signOutFilter<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/filter-name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;url-pattern<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>/*<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/url-pattern<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/filter-mapping<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<span style="color: #808080; font-style: italic;">&lt;!-- ... --&gt;</span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;listener<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;listener-class<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>org.jasig.cas.client.session.SingleSignOutHttpSessionListener<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/listener-class<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/listener<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></td></tr></tbody></table></div>
</pre>
<p>Notez enfin que <strong>le Single Sign-Out dépend du Single Sign-On</strong>, qui nécessite la <strong>mise en place du SSL</strong>.</p>
<h3>Conclusion</h3>
<p>Comme d&#8217;habitude, les sources sont disponibles sur le SVN du <a href="http://code.google.com/p/excilys/source/browse/projects#projects/ymca/tags/grails_cas">Google  Code</a> :</p>
<p><a href="https://excilys.googlecode.com/svn/projects/ymca/tags/grails_cas/">https://excilys.googlecode.com/svn/projects/ymca/tags/grails_cas/</a></p>
<p>J&#8217;espère vous avoir convaincu de la facilité à intégrer une application Grails à CAS, voir même vous avoir incité à découvrir CAS plus en profondeur, si ce n&#8217;était pas déjà le cas.</p>
<p>Et j&#8217;espère que vous ne me tiendrez pas trop rigueur de mes jeux de mots capilotractés <img src='http://blog.excilys.com/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> .</p>
<div id="_mcePaste" style="overflow: hidden; position: absolute; left: -10000px; top: 1211px; width: 1px; height: 1px;">&lt;?xml version=&#8221;1.0&#8243; encoding=&#8221;UTF-8&#8243;?&gt;<br />
&lt;project xmlns=&#8221;http://maven.apache.org/POM/4.0.0&#8243; xmlns:xsi=&#8221;http://www.w3.org/2001/XMLSchema-instance&#8221;<br />
xsi:schemaLocation=&#8221;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd&#8221;&gt;<br />
&lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;<br />
&lt;groupId&gt;com.excilys.blog&lt;/groupId&gt;<br />
&lt;artifactId&gt;cas&lt;/artifactId&gt;<br />
&lt;packaging&gt;war&lt;/packaging&gt;<br />
&lt;version&gt;1.0-SNAPSHOT&lt;/version&gt;</p>
<p>&lt;build&gt;<br />
&lt;plugins&gt;<br />
&lt;plugin&gt;<br />
&lt;artifactId&gt;maven-war-plugin&lt;/artifactId&gt;<br />
&lt;configuration&gt;<br />
&lt;warName&gt;cas&lt;/warName&gt;<br />
&lt;/configuration&gt;<br />
&lt;/plugin&gt;<br />
&lt;/plugins&gt;<br />
&lt;/build&gt;</p>
<p>&lt;dependencies&gt;<br />
&lt;dependency&gt;<br />
&lt;groupId&gt;org.jasig.cas&lt;/groupId&gt;<br />
&lt;artifactId&gt;cas-server-webapp&lt;/artifactId&gt;<br />
&lt;version&gt;${cas.version}&lt;/version&gt;<br />
&lt;type&gt;war&lt;/type&gt;<br />
&lt;scope&gt;runtime&lt;/scope&gt;<br />
&lt;/dependency&gt;</p>
<p>&lt;dependency&gt;<br />
&lt;groupId&gt;org.jasig.cas&lt;/groupId&gt;<br />
&lt;artifactId&gt;cas-server-support-generic&lt;/artifactId&gt;<br />
&lt;version&gt;${cas.version}&lt;/version&gt;<br />
&lt;type&gt;jar&lt;/type&gt;<br />
&lt;scope&gt;runtime&lt;/scope&gt;<br />
&lt;/dependency&gt;</p>
<p>&lt;/dependencies&gt;</p>
<p>&lt;properties&gt;<br />
&lt;cas.version&gt;3.3.5&lt;/cas.version&gt;<br />
&lt;/properties&gt;</p>
<p>&lt;repositories&gt;<br />
&lt;repository&gt;<br />
&lt;id&gt;ja-sig&lt;/id&gt;<br />
&lt;url&gt;http://developer.ja-sig.org/maven2/&lt;/url&gt;<br />
&lt;/repository&gt;<br />
&lt;/repositories&gt;<br />
&lt;/project&gt;</p></div>
<img src="http://feeds.feedburner.com/~r/blogexcilyscom/~4/l5Z-CtnJr8k" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.excilys.com/2010/05/06/cas-et-grails-sans-sarcasmes/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		<feedburner:origLink>http://blog.excilys.com/2010/05/06/cas-et-grails-sans-sarcasmes/</feedburner:origLink></item>
		<item>
		<title>Classes proxy en PHP : l’AOP des pauvres</title>
		<link>http://feedproxy.google.com/~r/blogexcilyscom/~3/A12QNoE8yIg/</link>
		<comments>http://blog.excilys.com/2010/04/30/classes-proxy-en-php-aop/#comments</comments>
		<pubDate>Fri, 30 Apr 2010 02:56:34 +0000</pubDate>
		<dc:creator>Bastien JANSEN</dc:creator>
				<category><![CDATA[Non classé]]></category>
		<category><![CDATA[aop]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[proxy]]></category>

		<guid isPermaLink="false">http://blog.excilys.com/?p=1557</guid>
		<description><![CDATA[Introduction
Dans cet article, nous allons voir comment mettre en œuvre le design pattern Proxy en PHP pour faire par exemple de l&#8217;AOP. Nous ne couvrirons qu&#8217;une petite partie du vaste domaine qu&#8217;est la programmation par aspects, pour des raisons de simplicité et de longueur d&#8217;article.
Commençons par la classique citation Wikipedia :
La programmation orientée aspect (POA, en anglais aspect-oriented [...]]]></description>
			<content:encoded><![CDATA[<h3>Introduction</h3>
<p>Dans cet article, nous allons voir comment mettre en œuvre le design pattern Proxy en PHP pour faire par exemple de l&#8217;AOP. Nous ne couvrirons qu&#8217;une petite partie du vaste domaine qu&#8217;est la programmation par aspects, pour des raisons de simplicité et de longueur d&#8217;article.</p>
<p>Commençons par la classique citation Wikipedia :</p>
<blockquote><p>La <strong>programmation orientée aspect</strong> (POA, en anglais <em>aspect-oriented programming</em> &#8211; AOP) est un paradigme de programmation qui permet de séparer les considérations techniques (<em>aspect</em> en anglais) des descriptions métier dans une application</p></blockquote>
<p><span style="font-style: normal;">L&#8217;utilisation de l&#8217;AOP permet ainsi de factoriser du code transverse tel que le </span>logging<span style="font-style: normal;"> des paramètres passés à une méthode, ou encore l&#8217;exécution d&#8217;une méthode au sein d&#8217;une transaction. On peut ainsi se concentrer sur le code métier dans la méthode</span><span style="font-style: normal;">.</span></p>
<address></address>
<p><span style="font-style: normal;">Nous allons mettre en œuvre une implémentation basique d&#8217;AOP en PHP. Je sais, le domaine d&#8217;expertise d&#8217;Excilys est bien le Java <img src='http://blog.excilys.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> .<span id="more-1557"></span></span></p>
<h3>Architecture</h3>
<p>Le but de cet exemple est d&#8217;être le moins intrusif possible. Dans le meilleur des cas, il faudrait que l&#8217;on puisse exécuter le code avec ou sans AOP sans avoir à le modifier. Comme je suis d&#8217;humeur flemmarde aujourd&#8217;hui (oui, c&#8217;est dimanche), je vais quand même être un peu plus souple sur cette règle. Nous allons faire en sorte de pouvoir utiliser ou non l&#8217;AOP en modifiant une seule ligne de code (l&#8217;instanciation de la classe). Bien sûr, dans une vraie application l&#8217;injection de dépendances ferait que je n&#8217;aurais même pas eu à écrire ce paragraphe.</p>
<p>Définissons quelques termes qui seront utilisés par la suite :</p>
<ul>
<li>Un <em>pointcut</em> est un endroit dans le code où nous allons utiliser l&#8217;AOP pour ajouter un comportement (par exemple l&#8217;entrée dans une méthode). Notez toutefois que l&#8217;AOP permet dans certains cas de remplacer le comportement d&#8217;une méthode.</li>
<li>Un <em>advice</em> est le comportement qui sera ajouté à un pointcut (par exemple afficher le nom de la méthode appelée).</li>
<li>Un <em>aspect</em> est la combinaison d&#8217;un ou plusieurs pointcut(s) et advice(s) (afficher le nom de la méthode appelée lorsque l&#8217;on entre dedans).</li>
</ul>
<p>Pour rester simple, nos pointcuts pourront être placés au début ou à la fin d&#8217;une méthode (et pas <em>autour</em>, par exemple). Ils contiendront l&#8217;advice, qui sera en fait un <em>callback</em> (donc une fonction ou une méthode de classe). Chaque pointcut pourra être associé à une ou plusieurs méthodes, et sera défini par :</p>
<ul>
<li>un nom de méthode exact,</li>
<li>un joker &#8216;*&#8217; pour « n&#8217;importe quelle méthode »,</li>
<li>ou une expression régulière , par exemple « <a href="http://blog.excilys.com/2010/01/29/les-dynamic-finders-du-pauvre/">findAll.*</a> »</li>
</ul>
<p>Pour pouvoir prendre en compte ces pointcuts et appeler les advices au moment voulu, nous allons <em>proxifier</em> l&#8217;instance sous AOPéïne, et tout bonnement intercepter tous les appels à ses méthodes. Pour cela, rien de tel qu&#8217;une bonne vieille composition. Notre classe Proxy va contenir l&#8217;instance dans un attribut, et chaque appel de méthode sera détecté grâce à la méthode magique <a href="http://fr.php.net/manual/fr/language.oop5.overloading.php#language.oop5.overloading.methods">__call()</a>. Elle est exécutée à chaque fois que l&#8217;on tente d&#8217;appeler une méthode non définie dans une classe (souvenez-vous, PHP est un langage dynamique <img src='http://blog.excilys.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> ).</p>
<p>Comme Proxy ne définit (presque) aucune méthode particulière, tous les appels passeront par __call(), ce qui nous permettra d&#8217;exécuter les advices puis la « vraie » méthode proxifiée.</p>
<h3>Implémentation</h3>
<p>Passons maintenant au code. Voici la classe Pointcut :</p>
<pre>
<div class="codecolorer-container php default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;height:300px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br />42<br />43<br />44<br />45<br />46<br />47<br />48<br />49<br />50<br />51<br />52<br />53<br />54<br />55<br />56<br />57<br /></div></td><td><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">&lt;?php</span><br />
<br />
<span style="color: #000000; font-weight: bold;">namespace</span> Pikwyx<span style="color: #339933;">;</span><br />
<br />
<span style="color: #009933; font-style: italic;">/**<br />
&nbsp;* A Pointcut is a place in a method where behavior will be added.<br />
&nbsp;*<br />
&nbsp;* @author bastien<br />
&nbsp;*/</span><br />
<span style="color: #000000; font-weight: bold;">class</span> Pointcut <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">const</span> BEFORE <span style="color: #339933;">=</span> <span style="color: #cc66cc;">1</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">const</span> AFTER <span style="color: #339933;">=</span> <span style="color: #cc66cc;">2</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #009933; font-style: italic;">/** The location of this Pointcut: at the begining or at the end of a method */</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000088;">$when</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009933; font-style: italic;">/** The behavior to add to the method */</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000088;">$callback</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009933; font-style: italic;">/** The method name or pattern to which the Pointcut is applied */</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000088;">$functionPattern</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009933; font-style: italic;">/** A flag indicating if $functionPattern is indeed a pattern */</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000088;">$isRegexp</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">function</span> __construct<span style="color: #009900;">&#40;</span><span style="color: #000088;">$when</span><span style="color: #339933;">,</span> <span style="color: #000088;">$functionPattern</span><span style="color: #339933;">,</span> <span style="color: #000088;">$callback</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">when</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$when</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">functionPattern</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$functionPattern</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">callback</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$callback</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">isRegexp</span> <span style="color: #339933;">=</span> <span style="color: #339933;">!</span><span style="color: #990000;">preg_match</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'/\w+/'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$functionPattern</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #009933; font-style: italic;">/**<br />
&nbsp; &nbsp; &nbsp;* Determines if the current Pointcut should be used for the given function.<br />
&nbsp; &nbsp; &nbsp;*<br />
&nbsp; &nbsp; &nbsp;* @param string $functionName the function which is called<br />
&nbsp; &nbsp; &nbsp;* @return boolean true if this Pointcut matches the function name, false otherwise<br />
&nbsp; &nbsp; &nbsp;*/</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> matches<span style="color: #009900;">&#40;</span><span style="color: #000088;">$functionName</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">isRegexp</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">functionPattern</span> <span style="color: #339933;">===</span> <span style="color: #0000ff;">'*'</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #009900; font-weight: bold;">true</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span> <span style="color: #b1b100;">else</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #990000;">preg_match</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">functionPattern</span><span style="color: #339933;">,</span> <span style="color: #000088;">$functionName</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span> <span style="color: #b1b100;">else</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #000088;">$functionName</span> <span style="color: #339933;">===</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">functionPattern</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> getWhen<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">when</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> getCallback<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">callback</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span><br />
<span style="color: #000000; font-weight: bold;">?&gt;</span></div></td></tr></tbody></table></div>
</pre>
<p>Pour nous faciliter la vie, la méthode <code class="codecolorer text default"><span class="text">matches</span></code> a été ajoutée pour déterminer si le Pointcut courant doit être utilisé pour la méthode en cours d&#8217;appel.</p>
<p>Voici à quoi ressemble la seconde classe, Proxy :</p>
<pre>
<div class="codecolorer-container php default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;height:300px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br />42<br />43<br />44<br />45<br />46<br />47<br />48<br />49<br />50<br />51<br />52<br />53<br />54<br />55<br />56<br />57<br />58<br />59<br />60<br />61<br />62<br />63<br />64<br />65<br />66<br />67<br />68<br />69<br />70<br />71<br />72<br />73<br />74<br />75<br />76<br />77<br />78<br />79<br />80<br />81<br />82<br />83<br /></div></td><td><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">&lt;?php</span><br />
<br />
<span style="color: #000000; font-weight: bold;">namespace</span> Pikwyx<span style="color: #339933;">;</span><br />
<br />
<span style="color: #b1b100;">require_once</span> <span style="color: #0000ff;">'Pointcut.php'</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #009933; font-style: italic;">/**<br />
&nbsp;* A class which wraps an instance of any class and allows to add behavior<br />
&nbsp;* before or after calling methods on this instance.<br />
&nbsp;*<br />
&nbsp;* @author bastien<br />
&nbsp;*/</span><br />
<span style="color: #000000; font-weight: bold;">class</span> Proxy <span style="color: #009900;">&#123;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #009933; font-style: italic;">/** The instance on which we want to add behavior */</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000088;">$proxifiedClass</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009933; font-style: italic;">/** An array of pointcuts to be placed before method calls */</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000088;">$beforePointcuts</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009933; font-style: italic;">/** An array of pointcuts to be placed after method calls */</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000088;">$afterPointcuts</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">function</span> __construct<span style="color: #009900;">&#40;</span><span style="color: #000088;">$proxifiedClass</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">proxifiedClass</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$proxifiedClass</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #009933; font-style: italic;">/**<br />
&nbsp; &nbsp; &nbsp;* Allows to add logic before a method is called on the instance.<br />
&nbsp; &nbsp; &nbsp;*<br />
&nbsp; &nbsp; &nbsp;* @param string $functionName the method on which to add behavior<br />
&nbsp; &nbsp; &nbsp;* @param callback $callback the behavior to add<br />
&nbsp; &nbsp; &nbsp;*/</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> doBefore<span style="color: #009900;">&#40;</span><span style="color: #000088;">$functionName</span><span style="color: #339933;">,</span> <span style="color: #000088;">$callback</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$pointcut</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Pointcut<span style="color: #009900;">&#40;</span>Pointcut<span style="color: #339933;">::</span><span style="color: #004000;">BEFORE</span><span style="color: #339933;">,</span> <span style="color: #000088;">$functionName</span><span style="color: #339933;">,</span> <span style="color: #000088;">$callback</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">beforePointcuts</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$pointcut</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #009933; font-style: italic;">/**<br />
&nbsp; &nbsp; &nbsp;* Allows to add logic after a method is called on the instance.<br />
&nbsp; &nbsp; &nbsp;*<br />
&nbsp; &nbsp; &nbsp;* @param string $functionName the method on which to add behavior<br />
&nbsp; &nbsp; &nbsp;* @param callback $callback the behavior to add<br />
&nbsp; &nbsp; &nbsp;*/</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> doAfter<span style="color: #009900;">&#40;</span><span style="color: #000088;">$functionName</span><span style="color: #339933;">,</span> <span style="color: #000088;">$callback</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$pointcut</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Pointcut<span style="color: #009900;">&#40;</span>Pointcut<span style="color: #339933;">::</span><span style="color: #004000;">AFTER</span><span style="color: #339933;">,</span> <span style="color: #000088;">$functionName</span><span style="color: #339933;">,</span> <span style="color: #000088;">$callback</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">afterPointcuts</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$pointcut</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #009933; font-style: italic;">/**<br />
&nbsp; &nbsp; &nbsp;* Magic function that intercepts any call to methods to allow advices to<br />
&nbsp; &nbsp; &nbsp;* be called.<br />
&nbsp; &nbsp; &nbsp;*<br />
&nbsp; &nbsp; &nbsp;* @param string $name the method name<br />
&nbsp; &nbsp; &nbsp;* @param mixed $arguments arguments to pass to the method<br />
&nbsp; &nbsp; &nbsp;*/</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> __call<span style="color: #009900;">&#40;</span><span style="color: #000088;">$name</span><span style="color: #339933;">,</span> <span style="color: #000088;">$arguments</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">runAdvices</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">beforePointcuts</span><span style="color: #339933;">,</span> <span style="color: #000088;">$name</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #990000;">is_array</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$arguments</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #990000;">call_user_func_array</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">proxifiedClass</span><span style="color: #339933;">,</span> <span style="color: #000088;">$name</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #000088;">$arguments</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span> <span style="color: #b1b100;">else</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #990000;">call_user_func</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">proxifiedClass</span><span style="color: #339933;">,</span> <span style="color: #000088;">$name</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #000088;">$arguments</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">runAdvices</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">afterPointcuts</span><span style="color: #339933;">,</span> <span style="color: #000088;">$name</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #009933; font-style: italic;">/**<br />
&nbsp; &nbsp; &nbsp;* Run the advices contained in the given list of pointcuts if they match<br />
&nbsp; &nbsp; &nbsp;* the given method name.<br />
&nbsp; &nbsp; &nbsp;*<br />
&nbsp; &nbsp; &nbsp;* @param array $pointcuts a list of Pointcut to match to the method<br />
&nbsp; &nbsp; &nbsp;* @param string $methodName the method which is called on the proxified class<br />
&nbsp; &nbsp; &nbsp;*/</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">function</span> runAdvices<span style="color: #009900;">&#40;</span><span style="color: #000088;">$pointcuts</span><span style="color: #339933;">,</span> <span style="color: #000088;">$methodName</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">foreach</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$pointcuts</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$pointcut</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">/* @var $pointcut Pointcut */</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$pointcut</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">matches</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$methodName</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #990000;">call_user_func</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$pointcut</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getCallback</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span><br />
<span style="color: #000000; font-weight: bold;">?&gt;</span></div></td></tr></tbody></table></div>
</pre>
<p>Les méthodes <code class="codecolorer text default"><span class="text">doBefore()</span></code> et <code class="codecolorer text default"><span class="text">doAfter()</span></code> permettent d&#8217;ajouter des pointcuts avant ou après une méthode de la classe proxifiée. Par la suite, lors de chaque appel, <code class="codecolorer text default"><span class="text">__call()</span></code> sera exécutée, et utilisera ces pointcuts avant et après avoir appelé la méthode proxifiée.</p>
<p>Nous utilisons massivement <a href="http://fr.php.net/call_user_func">call_user_func</a> <a name="note1"></a><a href="#note1_footer"><sup>[1]</sup></a>, qui est une fonction native de PHP permettant d&#8217;appeler une méthode par son nom contenu dans une chaine de caractères. Nous utilisons son premier argument sous forme de tableau, contenant également la référence vers l&#8217;objet sur lequel la méthode sera appelée.</p>
<p>Le « main » ressemblera donc à ceci :</p>
<pre>
<div class="codecolorer-container php default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br /></div></td><td><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">&lt;?php</span><br />
<br />
<span style="color: #b1b100;">require_once</span> <span style="color: #0000ff;">'Pikwyx/Proxy.php'</span><span style="color: #339933;">;</span><br />
<span style="color: #b1b100;">require_once</span> <span style="color: #0000ff;">'Foo.php'</span><span style="color: #339933;">;</span><br />
<span style="color: #b1b100;">require_once</span> <span style="color: #0000ff;">'FooAdvice.php'</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #000000; font-weight: bold;">use</span> Pikwyx\Proxy<span style="color: #339933;">;</span><br />
<br />
<span style="color: #000088;">$foo</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Proxy<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> Foo<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #000088;">$fooAdvice</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> FooAdvice<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #000088;">$foo</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">doBefore</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'doSomeStuff'</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$fooAdvice</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'onBefore'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #000088;">$foo</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">doAfter</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'doSomeStuff'</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$fooAdvice</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'onAfter'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #000088;">$foo</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">doSomeStuff</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'AOP'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></td></tr></tbody></table></div>
</pre>
<p>Avec :</p>
<pre>
<div class="codecolorer-container php default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br /></div></td><td><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">class</span> Foo <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> doSomeStuff<span style="color: #009900;">&#40;</span><span style="color: #000088;">$param</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;Hey, I'm doing some stuff with <span style="color: #006699; font-weight: bold;">$param</span>&lt;br/&gt;&quot;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #000000; font-weight: bold;">class</span> FooAdvice <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> onBefore<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;I'm just before the method call!&lt;br/&gt;&quot;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> onAfter<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;I'm just after the method call!&lt;br/&gt;&quot;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div>
</pre>
<p>On a ainsi ajouté deux pointcuts de « logging », avant et après <code class="codecolorer text default"><span class="text">doSomeStuff()</span></code>. Le résultat produit par ce script est sans surprise :</p>
<pre>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">I'm just before the method call!<br />
Hey, I'm doing some stuff with AOP<br />
I'm just after the method call!</div></td></tr></tbody></table></div>
</pre>
<p>Pour ne plus utiliser l&#8217;AOP, il suffit de remplacer <code class="codecolorer php default"><span class="php"><span style="color: #000088;">$foo</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Proxy<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> Foo<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></span></code> par <code class="codecolorer php default"><span class="php"><span style="color: #000088;">$foo</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Foo<span style="color: #339933;">;</span></span></code>.</p>
<h3>Et après ?</h3>
<p>Pour aller plus loin et écrire encore moins de code, il serait possible d&#8217;apporter les améliorations suivantes :</p>
<ul>
<li>Ajouter un pointcut entourant l&#8217;appel à une méthode, permettant par exemple de faire un try/catch.</li>
<li>Configuration des pointcuts dans un fichier XML (validé par une XSD), et récupération de l&#8217;instance du Proxy via une factory qui va se charger de lire la configuration et d&#8217;instancier automatiquement les Pointcuts.</li>
<li>Utiliser un framework d&#8217;injection de dépendances pour ne pas avoir à changer une ligne de code pour activer ou non l&#8217;AOP <img src='http://blog.excilys.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> .</li>
<li>Faire en sorte que la classe proxifiée puisse être reconnue comme étant une instance de Foo et non de Proxy (dans le cas où l&#8217;objet est passé à une méthode ayant des paramètres typés). C&#8217;est LE problème majeur de cette implémentation.</li>
<li>Intégrer les advices directement dans le code dans une version en cache de la classe Foo (ce qui pourrait corriger le point précédent), et mettre en place un <a href="http://fr.php.net/autoload">autoloader</a> qui permettra de créer/mettre à jour la version cachée si besoin, ou sinon de la renvoyer directement. On s&#8217;approcherait ainsi du <a href="http://www.eclipse.org/aspectj/doc/released/devguide/bytecode-concepts.html">bytecode weaving</a> d&#8217;AspectJ.</li>
</ul>
<h3>Conclusion</h3>
<p>Avec deux classes nous avons réussi à faire une ébauche d&#8217;AOP en PHP, ne nécessitant que peu de modifications dans du code existant. Même si l&#8217;approche est assez maladroite sur certains points (notamment le fait que l&#8217;instance de Proxy ne soit pas reconnue comme étant un objet de type Foo), avec quelques développements supplémentaires il serait possible d&#8217;obtenir des résultats rapidement intéressants. Reste à savoir si l&#8217;AOP est réellement utile dans une application PHP.</p>
<p><a name="note1_footer"></a><a href="#note1"><sup>[1]</sup></a> : non, cette fonction ne permet pas de téléphoner à l&#8217;utilisateur nommé &#8220;func&#8221;&#8230;</p>
<p><a href="http://blog.excilys.com/wp-content/uploads/2010/03/Pikwyx.zip">Code source</a></p>
<img src="http://feeds.feedburner.com/~r/blogexcilyscom/~4/A12QNoE8yIg" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.excilys.com/2010/04/30/classes-proxy-en-php-aop/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://blog.excilys.com/2010/04/30/classes-proxy-en-php-aop/</feedburner:origLink></item>
	</channel>
</rss>
