<?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, 09 Jan 2012 17:14:03 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<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>Des tests fonctionnels pour des projets mavenisés : un exemple concret avec Liferay</title>
		<link>http://feedproxy.google.com/~r/blogexcilyscom/~3/8nwp_REli5A/</link>
		<comments>http://blog.excilys.com/2012/01/09/des-tests-fonctionnels-pour-des-projets-mavenises/#comments</comments>
		<pubDate>Mon, 09 Jan 2012 17:13:10 +0000</pubDate>
		<dc:creator>Sophie Trinh-Khanh</dc:creator>
				<category><![CDATA[Non classé]]></category>
		<category><![CDATA[Jenkins]]></category>
		<category><![CDATA[maven]]></category>
		<category><![CDATA[Selenium]]></category>

		<guid isPermaLink="false">http://blog.excilys.com/?p=4162</guid>
		<description><![CDATA[Aujourd&#8217;hui je vous parlerai de la mise en place de tests fonctionnels dans le cadre de l&#8217;intégration continue, et l&#8217;illustrerai par un exemple concret de projet de type plugin se déployant dans un portail comme Liferay. En effet, plusieurs serveurs d&#8217;intégration (Hudson/Jenkins, Bamboo) permettent d&#8217;effectuer une série d&#8217;opérations sur le code après chaque commit sur [...]]]></description>
			<content:encoded><![CDATA[<p>Aujourd&#8217;hui je vous parlerai de la mise en place de <b>tests fonctionnels</b> dans le cadre de l&#8217;<b>intégration continue</b>, et l&#8217;illustrerai par un exemple concret de projet de type plugin se déployant dans un portail comme <a href="http://www.liferay.com/">Liferay</a>. En effet, plusieurs serveurs d&#8217;intégration (<a href="http://jenkins-ci.org/">Hudson/Jenkins</a>, <a href="http://www.atlassian.com/software/bamboo/overview">Bamboo</a>) permettent d&#8217;effectuer une série d&#8217;opérations sur le code après chaque commit sur le repository ou à heure définie, pour vérifier son intégrité et son bon comportement. Dans le monde de l&#8217;entreprise, une telle plateforme est souvent mise en place sur une machine dédiée, pour <b>vérifier la compilation</b>, <b>lancer les tests unitaires</b>, et <b>tenter le déploiement de l&#8217;application</b>. A la charge des développeurs, ou d&#8217;une équipe dédiée de testeurs, de voir si les nouveaux développements n&#8217;ont pas provoqué de régressions fonctionnelles sur le reste de l&#8217;application web&#8230; <span id="more-4162"></span></p>
<p>&nbsp;</p>
<h3>Et les tests fonctionnels ?</h3>
<p>&nbsp;</p>
<p>Justement, ils permettent d&#8217;effectuer de manière automatique, une <b>série de clics et de saisie clavier</b> pour effectuer un scénario fonctionnel. L&#8217;avantage, c&#8217;est qu&#8217;ils sont lancés automatiquement à chaque build et testent l&#8217;application de manière transverse via l&#8217;interface graphique. En effet, si les tests unitaires de deux classes isolées passent bien, le rendu de l&#8217;assemblage de ces deux briques peut ne pas être celui attendu.</p>
<p>&nbsp;</p>
<h3>Mais comment ça marche ?</h3>
<p style="text-align: right"><em>Selenium, of course !</em></p>
<p>&nbsp;</p>
<p>Des bibliothèques existent pour commander le navigateur, comme Selenium : il suffit de <b>programmer son scénario</b> avec Selenium API (existe en module Firefox ici : <a href="http://seleniumhq.org/download/">http://seleniumhq.org/download/</a>), et d&#8217;exporter le test dans son langage de prédilection : nous illustrerons par la suite un cas de test en Java.</p>
<p>Grâce à la bibliothèque Selenium, il suffit d&#8217;étendre <b>SeleneseTestCase</b> ou d&#8217;utiliser un objet de type <b>Selenium</b>. L&#8217;inconvénient de SeleneseTestCase est d&#8217;ouvrir et fermer le navigateur avant et après chaque test alors que ce n&#8217;est pas forcément utile. Il n&#8217;y a pas de distinction entre les annotations @Before et @BeforeClass.</p>
<p>Pour pallier à ce problème, on peut coder un test Selenium de cette manière :</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 />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 /></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.monprojet.monportlet.selenium</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">static</span> org.<span style="color: #006633;">junit</span>.<span style="color: #000000; font-weight: bold;">Assert</span>.<span style="color: #006633;">assertTrue</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.junit.After</span><span style="color: #339933;">;</span><br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.junit.AfterClass</span><span style="color: #339933;">;</span><br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.junit.Before</span><span style="color: #339933;">;</span><br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.junit.BeforeClass</span><span style="color: #339933;">;</span><br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.junit.Test</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">com.thoughtworks.selenium.DefaultSelenium</span><span style="color: #339933;">;</span><br />
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">com.thoughtworks.selenium.Selenium</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> NavigationIT <span style="color: #009900;">&#123;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">String</span> TIMEOUT_PAGE <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;30000&quot;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">static</span> Selenium selenium<span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; @BeforeClass<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #000066; font-weight: bold;">void</span> setUp<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">Exception</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003399;">String</span> url <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;http://localhost:8080/liferay/&quot;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; selenium <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> DefaultSelenium<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;localhost&quot;</span>, <span style="color: #cc66cc;">4444</span>, <span style="color: #0000ff;">&quot;*firefox&quot;</span>, url<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; selenium.<span style="color: #006633;">start</span><span style="color: #009900;">&#40;</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; @AfterClass<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #000066; font-weight: bold;">void</span> tearDown<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; selenium.<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; selenium.<span style="color: #006633;">stop</span><span style="color: #009900;">&#40;</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; @Before<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> beforeLogin<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; selenium.<span style="color: #006633;">open</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; selenium.<span style="color: #006633;">waitForPageToLoad</span><span style="color: #009900;">&#40;</span>TIMEOUT_PAGE<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; @After<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> afterLogout<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; @Test<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> testPorletAffiche<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; assertTrue<span style="color: #009900;">&#40;</span>selenium.<span style="color: #006633;">isTextPresent</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Portlet Agenda&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div>
</pre>
<p>Nous venons donc de coder un test fonctionnel qui à travers le navigateur Firefox, ouvre une nouvelle page, accède à l&#8217;URL <i>http://localhost:8080/liferay/</i>, attend que la page soit chargée, se logge, et vérifie que le texte &#8220;Portlet Agenda&#8221; est bien présent.</p>
<p>&nbsp;</p>
<h3>Et une fois le scénario écrit, comment automatiser les tests ?</h3>
<p style="text-align: right"><em>Pom Maven, Surefire, Ant, et autres douceurs&#8230;</em></p>
<p>&nbsp;</p>
<p>Avec Maven, on configure un <b>nouveau profil spécifique aux tests fonctionnels</b>. En effet, on s&#8217;arrange pour ne pas effectuer ces tests un peu longs dans le profil par défaut du build Maven. Cela permet de gagner du temps dans le développement et de ne pas être dérangé par des fenêtres Firefox intempestives&#8230;</p>
<p>Dans le pom du projet, on ajoute donc le profil &#8220;integration-test&#8221; :</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 /></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;profiles<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;profile<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;id<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>integration-test<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/id<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;activation<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;activeByDefault<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>false<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/activeByDefault<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;/activation<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;build<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;/build<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;/profile<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/profiles<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></td></tr></tbody></table></div>
</pre>
<p>Le build prend en compte cette configuration quand on lance le build Maven via la commande :</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 clean install -Pintegration-test</div></td></tr></tbody></table></div>
</pre>
<p>&nbsp;</p>
<h4>Plugin maven-surefire</h4>
<p>&nbsp;</p>
<p>On utilise Surefire pour lancer les tests situés dans un certain package. Si ce plugin est utilisé pour exécuter les tests unitaires JUnit, rien n&#8217;empêche de l&#8217;appliquer aux tests Selenium qui seront traités de la même manière.</p>
<p>Entre les balises <em>&lt;build&gt;&lt;/build&gt;</em>, on ajoute :</p>
<pre>
<div class="codecolorer-container xml 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 /></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;plugins<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;plugin<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;groupId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>org.apache.maven.plugins<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; &nbsp; &nbsp; &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>maven-surefire-plugin<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; &nbsp; &nbsp; &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>${surefire.plugin.version}<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 />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;executions<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;">&lt;!-- Tests d'integration --&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;execution<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;id<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>surefire-integration-tests<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/id<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;phase<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>integration-test<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/phase<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;goals<span style="color: #000000; font-weight: bold;">&gt;</span></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;goal<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>test<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/goal<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;/goals<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;configuration<span style="color: #000000; font-weight: bold;">&gt;</span></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;skip<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>false<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/skip<span style="color: #000000; font-weight: bold;">&gt;</span></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;includes<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;include<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>**/selenium/**IT.java<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/include<span style="color: #000000; font-weight: bold;">&gt;</span></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;/includes<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;/configuration<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;/execution<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;/executions<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;/plugin<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/plugins<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></td></tr></tbody></table></div>
</pre>
<p>On va donc, pendant la <b>phase integration-test</b>, lancer les tests situés dans <i>src/test/java/&#8230;/selenium/</i> dont le nom de classe se termine par IT.</p>
<p>&nbsp;</p>
<h4>Plugin selenium-maven</h4>
<p>&nbsp;</p>
<p>Avant de pouvoir lancer les tests d&#8217;intégration fonctionnels, il faut démarrer <b>Selenium RC</b> de manière automatique, et ensuite l&#8217;arrêter. En effet, Selenium &#8220;Remote Control&#8221; agit comme un proxy HTTP pour exécuter les requêtes navigateurs.</p>
<p>Entre les balises <em>&lt;plugins&gt;&lt;/plugins&gt;</em>, on ajoute :</p>
<pre>
<div class="codecolorer-container xml 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 /></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;plugin<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;groupId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>org.codehaus.mojo<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; &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>selenium-maven-plugin<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; &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>${selenium.plugin.version}<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 />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;executions<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;">&lt;!-- Demarrage du serveur SeleniumRC --&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;execution<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;id<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>start<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/id<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;phase<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>pre-integration-test<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/phase<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;goals<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;goal<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>start-server<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/goal<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;/goals<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;configuration<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;background<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>true<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/background<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;/configuration<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;/execution<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;">&lt;!-- Arret du serveur SeleniumRC --&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;execution<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;id<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>stop<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/id<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;phase<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>post-integration-test<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/phase<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;goals<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;goal<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>stop-server<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/goal<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;/goals<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;/execution<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;/executions<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/plugin<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></td></tr></tbody></table></div>
</pre>
<p>&nbsp;</p>
<h4>Plugin maven-antrun</h4>
<p>&nbsp;</p>
<p>Pour effectuer les tests fonctionnels, on a souvent besoin de déployer ses applications web au sein d&#8217;un <b>conteneur de servlets</b> de type Apache Tomcat, dont on doit pouvoir gérer le démarrage et l&#8217;extinction. C&#8217;est le cas pour une application se basant sur le portail Liferay, pour laquelle il faut aussi gérer le redéploiement de tous les plugins développés.</p>
<p>Pour cela, on crée un <b>script de tâches Ant</b>. Le gros avantage est de maîtriser l&#8217;ordre des commandes exécutées, alors que ce n&#8217;est pas forcément le cas lorsqu&#8217;on utilise des plugins dédiés différents dans une même phase.</p>
<p>Voici un exemple d&#8217;utilisation des tâches Ant dans un script pour Tomcat, qui démarre le serveur, attend le déploiement de la webapp Liferay, déploie une autre webapp qui est en fait un plugin Liferay, et arrête finalement le serveur. En phase de post-integration-test, on effectue les tâches contraires :</p>
<pre>
<div class="codecolorer-container xml 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 /></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;properties<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;antrun.plugin.version<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>1.7<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/antrun.plugin.version<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;monprojet.monportlet.it.tomcat.dir<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>/opt/tomcat-liferay<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/monprojet.monportlet.it.tomcat.dir<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;monprojet.monportlet.it.liferay.auto.deploy.dir<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>/opt/tomcat-liferay/liferay-deploy<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/monprojet.monportlet.it.liferay.auto.deploy.dir<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;monprojet.monportlet.it.liferay.version<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>6.0.6<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/monprojet.monportlet.it.liferay.version<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;monprojet.monportlet.it.url.liferay<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>http://localhost:8080/liferay<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/monprojet.monportlet.it.url.liferay<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/properties<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;plugin<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;groupId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>org.apache.maven.plugins<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; &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>maven-antrun-plugin<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; &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>${antrun.plugin.version}<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 />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;executions<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;">&lt;!-- Demarrage de Tomcat, deploiement du portail Liferay, deploiement des portlets --&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;execution<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;id<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>start-liferay<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/id<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;phase<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>pre-integration-test<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/phase<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;configuration<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;target<span style="color: #000000; font-weight: bold;">&gt;</span></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;echo<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Starting Tomcat and Liferay server...<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/echo<span style="color: #000000; font-weight: bold;">&gt;</span></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;echo<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Tomcat directory : ${monprojet.monportlet.it.tomcat.dir}<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/echo<span style="color: #000000; font-weight: bold;">&gt;</span></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;echo<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Liferay auto-deploy directory : ${monprojet.monportlet.it.liferay.auto.deploy.dir}<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/echo<span style="color: #000000; font-weight: bold;">&gt;</span></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;echo<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Liferay version : ${monprojet.monportlet.it.liferay.version}<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/echo<span style="color: #000000; font-weight: bold;">&gt;</span></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;exec</span> <span style="color: #000066;">dir</span>=<span style="color: #ff0000;">&quot;${monprojet.monportlet.it.tomcat.dir}/bin&quot;</span> <span style="color: #000066;">executable</span>=<span style="color: #ff0000;">&quot;${monprojet.monportlet.it.tomcat.dir}/bin/startup.sh&quot;</span></span><br />
<span style="color: #009900;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000066;">failonerror</span>=<span style="color: #ff0000;">&quot;true&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;echo<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Start signal send<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/echo<span style="color: #000000; font-weight: bold;">&gt;</span></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;echo<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Waiting for Liferay portal to be deployed...<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/echo<span style="color: #000000; font-weight: bold;">&gt;</span></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;waitfor</span> <span style="color: #000066;">maxwait</span>=<span style="color: #ff0000;">&quot;5&quot;</span> <span style="color: #000066;">maxwaitunit</span>=<span style="color: #ff0000;">&quot;minute&quot;</span> <span style="color: #000066;">checkevery</span>=<span style="color: #ff0000;">&quot;1000&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;http</span> <span style="color: #000066;">url</span>=<span style="color: #ff0000;">&quot;${monprojet.monportlet.it.url.liferay}/&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;/waitfor<span style="color: #000000; font-weight: bold;">&gt;</span></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;echo<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Liferay deployed !<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/echo<span style="color: #000000; font-weight: bold;">&gt;</span></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;echo<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Copying ${artifactId}-${version}.war into Liferay auto-deploy directory...<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/echo<span style="color: #000000; font-weight: bold;">&gt;</span></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;copy</span> <span style="color: #000066;">file</span>=<span style="color: #ff0000;">&quot;${basedir}/target/${artifactId}-${version}.war&quot;</span> <span style="color: #000066;">tofile</span>=<span style="color: #ff0000;">&quot;${monprojet.monportlet.it.liferay.auto.deploy.dir}/${artifactId}.war&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;echo<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>${artifactId}.war copied !<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/echo<span style="color: #000000; font-weight: bold;">&gt;</span></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;echo<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Waiting for ${artifactId} to be deployed...<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/echo<span style="color: #000000; font-weight: bold;">&gt;</span></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;waitfor</span> <span style="color: #000066;">maxwait</span>=<span style="color: #ff0000;">&quot;5&quot;</span> <span style="color: #000066;">maxwaitunit</span>=<span style="color: #ff0000;">&quot;minute&quot;</span> <span style="color: #000066;">checkevery</span>=<span style="color: #ff0000;">&quot;5000&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;http</span> <span style="color: #000066;">url</span>=<span style="color: #ff0000;">&quot;${monprojet.monportlet.it.url}/${artifactId}/&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;/waitfor<span style="color: #000000; font-weight: bold;">&gt;</span></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;echo<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Portlet deployed !<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/echo<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;/target<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;/configuration<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;goals<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;goal<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>run<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/goal<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;/goals<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;/execution<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;">&lt;!-- Arret de Tomcat --&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;execution<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;id<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>stop-liferay<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/id<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;phase<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>post-integration-test<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/phase<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;configuration<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;target<span style="color: #000000; font-weight: bold;">&gt;</span></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;echo<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Shutting down Tomcat server...<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/echo<span style="color: #000000; font-weight: bold;">&gt;</span></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;exec</span> <span style="color: #000066;">dir</span>=<span style="color: #ff0000;">&quot;${monprojet.monportlet.it.tomcat.dir}/bin&quot;</span> <span style="color: #000066;">executable</span>=<span style="color: #ff0000;">&quot;${monprojet.monportlet.it.tomcat.dir}/bin/shutdown.sh&quot;</span></span><br />
<span style="color: #009900;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000066;">failonerror</span>=<span style="color: #ff0000;">&quot;true&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;echo<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Stop signal send<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/echo<span style="color: #000000; font-weight: bold;">&gt;</span></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;echo<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Waiting 15 seconds for Tomcat to stop...<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/echo<span style="color: #000000; font-weight: bold;">&gt;</span></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;waitfor</span> <span style="color: #000066;">maxwait</span>=<span style="color: #ff0000;">&quot;15&quot;</span> <span style="color: #000066;">maxwaitunit</span>=<span style="color: #ff0000;">&quot;second&quot;</span> <span style="color: #000066;">checkevery</span>=<span style="color: #ff0000;">&quot;15000&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;available</span> <span style="color: #000066;">file</span>=<span style="color: #ff0000;">&quot;inexistant.log&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;/waitfor<span style="color: #000000; font-weight: bold;">&gt;</span></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;echo<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Undeploying portlet ${artifactId}...<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/echo<span style="color: #000000; font-weight: bold;">&gt;</span></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;delete</span> <span style="color: #000066;">includeemptydirs</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">verbose</span>=<span style="color: #ff0000;">&quot;false&quot;</span> <span style="color: #000066;">failonerror</span>=<span style="color: #ff0000;">&quot;true&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;fileset</span> <span style="color: #000066;">dir</span>=<span style="color: #ff0000;">&quot;${monprojet.monportlet.it.tomcat.dir}/webapps/&quot;</span> <span style="color: #000066;">includes</span>=<span style="color: #ff0000;">&quot;${artifactId}/**&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;/delete<span style="color: #000000; font-weight: bold;">&gt;</span></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;echo<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Portlet undeployed !<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/echo<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;/target<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;/configuration<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;goals<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;goal<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>run<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/goal<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;/goals<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;/execution<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;/executions<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/plugin<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></td></tr></tbody></table></div>
</pre>
<p>&nbsp;</p>
<h3>Et si je souhaite lancer mes tests fonctionnels en local et/ou sur la machine d&#8217;intégration ?</h3>
<p style="text-align: right"><em>Profil Maven</em></p>
<p>&nbsp;</p>
<p>Il suffit de paramétrer deux configurations différentes, et de rendre le projet indépendant de ces paramètres qui seront eux propres à chaque machine.</p>
<p>Pour cela, on configure le fichier <b>settings.xml</b> (dans <i>C:\Users\Nom\.m2\</i>, <i>/home/user/.m2</i> ou <i>/opt/maven/conf</i>) chargé avant chaque build Maven. Après avoir repéré le profil par défaut, on ajoute nos propriétés : elles se nomment convenablement pour ne pas mélanger les configurations entre projets.</p>
<p>On doit obtenir quelque chose du type :</p>
<pre>
<div class="codecolorer-container xml 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 /></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;settings<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;mirrors<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; ...<br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/mirrors<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;profiles<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;profile<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;id<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>BLR<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/id<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;activation<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;activeByDefault<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>true<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/activeByDefault<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;/activation<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;properties<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;monprojet.monportlet.it.propriete1<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>valeur1<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/monprojet.monportlet.it.propriete1<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;monprojet.monportlet.it.propriete2<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>valeur2<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/monprojet.monportlet.it.propriete2<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;/properties<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;repositories<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ...<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/repositories<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;pluginRepositories<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ...<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/pluginRepositories<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;/profile<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;/profiles<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;servers<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; ...<br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/servers<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/settings<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></td></tr></tbody></table></div>
</pre>
<p>Dans notre cas on déplace le bloc des propriétés <b>définissant l&#8217;environnement</b> Liferay du pom vers settings.xml :</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 /></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;properties<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;monprojet.monportlet.it.tomcat.dir<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>/opt/tomcat-liferay<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/monprojet.monportlet.it.tomcat.dir<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;monprojet.monportlet.it.liferay.auto.deploy.dir<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>/opt/tomcat-liferay/liferay-deploy<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/monprojet.monportlet.it.liferay.auto.deploy.dir<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;monprojet.monportlet.it.liferay.version<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>6.0.6<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/monprojet.monportlet.it.liferay.version<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;monprojet.monportlet.it.url.liferay<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>http://localhost:8080/liferay<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/monprojet.monportlet.it.url.liferay<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/properties<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></td></tr></tbody></table></div>
</pre>
<p>Dans le pom, on peut alors faire appel aux variables qui sont disponibles pour tous les projets en utilisant la syntaxe :</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">${monprojet.monportlet.it.tomcat.dir}</div></td></tr></tbody></table></div>
</pre>
<p>&nbsp;</p>
<h3>Il reste l&#8217;URL en dur dans le test Selenium !</h3>
<p style="text-align: right"><em>Filters et properties</em></p>
<p>&nbsp;</p>
<p>Parfois, on a également besoin d&#8217;utiliser une propriété de settings.xml dans une classe de test Selenium : pour définir l&#8217;adresse où s&#8217;effectuent les tests Selenium par exemple :</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">selenium <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> DefaultSelenium<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;localhost&quot;</span>, <span style="color: #cc66cc;">4444</span>, <span style="color: #0000ff;">&quot;*firefox&quot;</span>, url<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
selenium.<span style="color: #006633;">start</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></td></tr></tbody></table></div>
</pre>
<p>Ici on veut que &#8220;url&#8221; prenne la valeur de la propriété qui est définie dans settings.xml et qui est prise en compte lorsque le pom du projet est parsé.</p>
<p>Pour cela, on crée un fichier <strong>it.properties</strong> dans <i>src/test/resources</i>, qui contient par exemple :</p>
<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 /></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: #000080; font-weight:bold;">projet-url</span><span style="color: #000000;">=</span><span style="color: #008000; font-weight:bold;">$<span style="">&#123;</span>monprojet.monportlet.it.url<span style="">&#125;</span></span></div></td></tr></tbody></table></div>
</pre>
<p>(monprojet.monportlet.it.url est une propriété définie dans settings.xml)</p>
<p>On définit ensuite un <b>filtre</b> dans pom.xml, qui permet d&#8217;assigner les variables dans ce fichier lors des <b>phases de tests</b>. Entre les balises <em>&lt;build&gt;&lt;/build&gt;</em> du profil &#8220;integration-test&#8221;, on ajoute :</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 /></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;testResources<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;testResource<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;directory<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>src/test/resources<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/directory<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;filtering<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>true<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/filtering<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;/testResource<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/testResources<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></td></tr></tbody></table></div>
</pre>
<p>Dans la classe de test, on peut alors écrire :</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"><span style="color: #003399;">Properties</span> props <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 />
props.<span style="color: #006633;">load</span><span style="color: #009900;">&#40;</span><span style="color: #003399;">ClassLoader</span>.<span style="color: #006633;">getSystemResource</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;it.properties&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">openStream</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 />
<span style="color: #003399;">String</span> url <span style="color: #339933;">=</span> props.<span style="color: #006633;">getProperty</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;projet-url&quot;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">+</span> <span style="color: #0000ff;">&quot;/&quot;</span><span style="color: #339933;">;</span><br />
<br />
selenium <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> DefaultSelenium<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;localhost&quot;</span>, <span style="color: #cc66cc;">4444</span>, <span style="color: #0000ff;">&quot;*firefox&quot;</span>, url<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
selenium.<span style="color: #006633;">start</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></td></tr></tbody></table></div>
</pre>
<p>&nbsp;</p>
<h3>Tout ça pour rien, ma machine d&#8217;intégration ne dispose pas d&#8217;environnement graphique&#8230;</h3>
<p style="text-align: right"><em>Xvfb et jargon d&#8217;admin</em></p>
<p>&nbsp;</p>
<p>Que nenni ! Il est possible de configuer un <b>serveur xvfb</b> pour rediriger la sortie graphique et effectuer vos tests dans un navigateur &#8220;invisible&#8221;.</p>
<p>Ce sera une étape obligatoire si, en lançant le build Maven avec le profil d&#8217;intégration, vous obtenez l&#8217;erreur frustrante :</p>
<pre><span style="color: #ff0000">java.lang.RuntimeException: Timed out waiting for profile to be created!
Failed to start new browser session: Error while launching browser on session null
</span></pre>
<p>&nbsp;</p>
<p>Cette erreur s&#8217;accompagne d&#8217;un warning en jaune dans la console de Jenkins :</p>
<pre>
Waiting for Selenium Server...
<span style="color: #ff9900">[WARNING] OS appears to be Unix and no DISPLAY environment variable has been detected. Browser maybe unable to function correctly. Consider using the selenium:xvfb goal to enable headless operation.
</span></pre>
<p>&nbsp;</p>
<p>Cela signifie que la machine sur laquelle vous tentez de lancer les tests fonctionnels ne dispose <b>pas d&#8217;environnement graphique</b>. On ne peut donc pas lancer la commande &#8220;firefox&#8221; pour ouvrir un navigateur.</p>
<p>Il faut demander à un administrateur d&#8217;effectuer les modifications suivantes sur la machine :</p>
<ul>
<li>installer le package <b>xvfb</b> (un X11 server)</li>
<li>installer le package <b>iceweasel</b> (firefox pour une Debian)</li>
<li>configurer le display pour pouvoir exécuter des applications graphiques comme firefox : <b>export DISPLAY=:99</b> (ou autre valeur), dans le contexte utilisé au lancement de Jenkins par exemple.</li>
<li>tester en lancant la commande Xvfb (il choisit le DISPLAY automatiquement), et lancer firefox en ligne de commande. Cela doit être fait avec le même utilisateur que celui qui lance Jenkins.</li>
</ul>
<p>&nbsp;<br />
&nbsp;<br />
C&#8217;est fini ! Lancez autant de build maven en profil &#8220;integration-test&#8221; que vous souhaitez pour vous féliciter <img src='http://blog.excilys.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p><!--[if IE]><iframe frameborder="0" allowTransparency="true" class="addtoany_special_service twitter_tweet" src="http://platform.twitter.com/widgets/tweet_button.html?url=http%3A%2F%2Fblog.excilys.com%2F2012%2F01%2F09%2Fdes-tests-fonctionnels-pour-des-projets-mavenises%2F&amp;counturl=http%3A%2F%2Fblog.excilys.com%2F2012%2F01%2F09%2Fdes-tests-fonctionnels-pour-des-projets-mavenises%2F&amp;count=horizontal&amp;text=Des%20tests%20fonctionnels%20pour%20des%20projets%20mavenis%C3%A9s%20%3A%20un%20exemple%20concret%20avec%20Liferay" scrolling="no" style="border:none;overflow:hidden;width:130px;height:20px"></iframe><![endif]--><!--[if !IE]><!--><iframe class="addtoany_special_service twitter_tweet" src="http://platform.twitter.com/widgets/tweet_button.html?url=http%3A%2F%2Fblog.excilys.com%2F2012%2F01%2F09%2Fdes-tests-fonctionnels-pour-des-projets-mavenises%2F&amp;counturl=http%3A%2F%2Fblog.excilys.com%2F2012%2F01%2F09%2Fdes-tests-fonctionnels-pour-des-projets-mavenises%2F&amp;count=horizontal&amp;text=Des%20tests%20fonctionnels%20pour%20des%20projets%20mavenis%C3%A9s%20%3A%20un%20exemple%20concret%20avec%20Liferay" scrolling="no" style="border:none;overflow:hidden;width:130px;height:20px"></iframe><!--<![endif]--><!--[if IE]><iframe frameborder="0" allowTransparency="true" class="addtoany_special_service google_plusone" src="https://plusone.google.com/u/0/_/%2B1/fastbutton?url=http%3A%2F%2Fblog.excilys.com%2F2012%2F01%2F09%2Fdes-tests-fonctionnels-pour-des-projets-mavenises%2F&amp;size=medium&amp;count=true" scrolling="no" style="border:none;overflow:hidden;width:90px;height:20px"></iframe><![endif]--><!--[if !IE]><!--><iframe class="addtoany_special_service google_plusone" src="https://plusone.google.com/u/0/_/%2B1/fastbutton?url=http%3A%2F%2Fblog.excilys.com%2F2012%2F01%2F09%2Fdes-tests-fonctionnels-pour-des-projets-mavenises%2F&amp;size=medium&amp;count=true" scrolling="no" style="border:none;overflow:hidden;width:90px;height:20px"></iframe><!--<![endif]--><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fblog.excilys.com%2F2012%2F01%2F09%2Fdes-tests-fonctionnels-pour-des-projets-mavenises%2F&amp;title=Des%20tests%20fonctionnels%20pour%20des%20projets%20mavenis%C3%A9s%20%3A%20un%20exemple%20concret%20avec%20Liferay" id="wpa2a_2"><img src="http://blog.excilys.com/wp-content/plugins/add-to-any/share_save_120_16.png" width="120" height="16" alt="Share"/></a></p><img src="http://feeds.feedburner.com/~r/blogexcilyscom/~4/8nwp_REli5A" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.excilys.com/2012/01/09/des-tests-fonctionnels-pour-des-projets-mavenises/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://blog.excilys.com/2012/01/09/des-tests-fonctionnels-pour-des-projets-mavenises/</feedburner:origLink></item>
		<item>
		<title>Radio Liferay Episode 1: James Falkner</title>
		<link>http://feedproxy.google.com/~r/blogexcilyscom/~3/sbKj8O6ulak/</link>
		<comments>http://blog.excilys.com/2011/12/06/radio-liferay-episode-1-james-falkner/#comments</comments>
		<pubDate>Tue, 06 Dec 2011 16:46:48 +0000</pubDate>
		<dc:creator>Anthony COULON</dc:creator>
				<category><![CDATA[Non classé]]></category>
		<category><![CDATA[Liferay]]></category>
		<category><![CDATA[Podcast]]></category>

		<guid isPermaLink="false">http://blog.excilys.com/?p=3777</guid>
		<description><![CDATA[&#160; &#160; Olaf Kock, de Liferay Allemagne, a eu l&#8217;idée d&#8217;enregistrer des entretiens avec différentes personnes travaillant chez Liferay et de les diffuser sous forme de podcast sur liferay.com. Chacun des épisodes nous permet de découvrir plus en profondeur l&#8217;univers Liferay et ses acteurs. Dans ce premier épisode, Olaf interroge James Falkner sur la communauté Liferay. &#160; [...]]]></description>
			<content:encoded><![CDATA[<div style="text-align: justify"><a href="http://blog.excilys.com/wp-content/uploads/2011/11/radio_liferay.png"><img class="size-thumbnail wp-image-4010 alignleft" src="http://blog.excilys.com/wp-content/uploads/2011/11/radio_liferay-150x150.png" alt="" width="150" height="150" /></a></div>
<div style="text-align: justify">
<p>&nbsp;</p>
<p><a href="http://blog.excilys.com/wp-content/uploads/2011/11/liferay1.jpg"><img class="alignnone size-full wp-image-4022" src="http://blog.excilys.com/wp-content/uploads/2011/11/liferay1.jpg" alt="" width="419" height="120" /></a></p>
<p>&nbsp;</p>
<p>Olaf Kock, de Liferay Allemagne, a eu l&#8217;idée d&#8217;enregistrer des entretiens avec différentes personnes travaillant chez Liferay et de les diffuser sous forme de podcast sur <a href="http://www.liferay.com/">liferay.com</a>. Chacun des épisodes nous permet de découvrir plus en profondeur l&#8217;univers Liferay et ses acteurs.</p>
<p dir="ltr">Dans ce premier épisode, Olaf interroge James Falkner sur la communauté Liferay.</p>
<p><span id="more-3777"></span><br />
&nbsp;</p>
</div>
<div style="text-align: justify">
<p dir="ltr">Après l&#8217;obtention de son diplôme à l’université de Floride, la carrière de James Falkner a débuté en 1997 au sein de Sun Microsystem. Son interêt pour l’open source l&#8217;a poussé à intégrer le projet Sun Portal en 2008 et à poursuivre dans cette voie en rejoignant la communauté Liferay en 2010 en tant que Community Manager.</p>
<p>&nbsp;</p>
</div>
<div style="text-align: justify">
<h3>La communauté Liferay en chiffres</h3>
<p dir="ltr">La communauté Liferay est actuellement composée d&#8217;environ 50 000 membres enregistrés sur <a href="http://www.liferay.com/">liferay.com</a>, repartis comme ceci :</p>
<p dir="ltr"><a href="http://blog.excilys.com/wp-content/uploads/2011/11/chart_1.png"><img class="alignleft size-full wp-image-3995" src="http://blog.excilys.com/wp-content/uploads/2011/11/chart_1.png" alt="" width="417" height="257" /></a><a href="http://blog.excilys.com/wp-content/uploads/2011/11/chart_2.png"><img class="size-full wp-image-3996 alignnone" src="http://blog.excilys.com/wp-content/uploads/2011/11/chart_2.png" alt="" width="417" height="257" /></a></p>
<p dir="ltr">&nbsp;</p>
<p dir="ltr">La communauté est très active comme en témoigne la partie <a href="http://www.liferay.com/community/forums">forum</a>, actuellement composée de plus de 170 000 messages, répartis dans un peu plus de 80 catégories, et où 100 à 150 messages sont postés quotidiennement.</p>
<p>&nbsp;</p>
</div>
<div style="text-align: justify">
<h3>User Group</h3>
<p dir="ltr">Bien que présents depuis l&#8217;origine de Liferay, les User Groups ont toujours été indépendants de la compagnie. Ce n&#8217;est que récemment que Liferay a décidé de formaliser et d&#8217;intégrer leur présence sur le site de la version communautaire <a href="http://www.liferay.com/community/user-groups"></a><a href="http://www.liferay.org/">liferay.org</a>. La compagnie veut favoriser leur expansion et ainsi développer leur atout social.</p>
<p dir="ltr">A la création d’un User Group sur <a href="http://www.liferay.org/">liferay.org</a>, des ressources et des outils collaboratifs sont mis à la disposition des membres gratuitement, ce qui permet une meilleure collaboration entre les membres ainsi qu’une gestion totalement autonome du groupe. Les membres des groupes peuvent donc facilement organiser des rencontres et collaborer ensemble.</p>
<p>&nbsp;</p>
</div>
<div style="text-align: justify">
<h3>Community Leadership</h3>
<p dir="ltr">Une communauté open source qui fonctionne amène naturellement des leaders. Ils pourront ainsi encadrer les membres de la communauté grâce à leurs compétences et à leurs expériences.</p>
<p dir="ltr">Pour les volontaires qui veulent investir de leur temps dans la communauté, Liferay possède trois sous programmes :</p>
<ul>
<li>
<p dir="ltr">le <em>100 papercuts, </em>inspiré de la communauté Ubuntu, dans lequel un petit groupe de personnes se focalisent sur la résolution de 100 bugs ennuyeux mais facile à résoudre, en un temps limité.</p>
</li>
</ul>
<ul>
<li>
<p dir="ltr">le <em>Community verify program :</em> du fait de l’immensité actuelle du projet, des droits supplémentaires au Bug Tracking System sont ajoutés aux volontaires afin de leur déléguer la recherche de bug dans le système.</p>
</li>
</ul>
<ul>
<li>
<p dir="ltr">le <em>Bug squad, </em>programme le plus récent, où les volontaires apportent leur aide pour faciliter les releases majeures. Ils ont accès en avant première à la version pour la tester, découvrir les nouvelles fonctionnalités et donner leurs ressentis. Ces retours permettront d’améliorer les points perfectibles (bugs, améliorations ratées, …).</p>
</li>
</ul>
<p dir="ltr">Si vous êtes prêts à vous investir contactez <a href="http://www.liferay.com/web/james.falkner/profile">James Falkner</a>.</p>
<p>&nbsp;</p>
</div>
<div style="text-align: justify">
<h3>Date de release</h3>
<p>Il sort en moyenne une version majeure de Liferay tous les ans. Mais le jour officiel de sortie est toujours annoncé tardivement, la compagnie préférant annoncer aux utilisateurs une fenêtre de 4 à 6 semaines.</p>
<p>La dernière version (6.0) étant sortie en septembre 2010,  la prochaine (6.1) est annoncée, au moment de l’enregistrement du podcast, pour fin septembre &#8211; début octobre.</p>
<p dir="ltr">La version suivante, hypothétiquement 6.2, devrait logiquement arriver au début du quatrième trimestre 2012.</p>
<p><em>Note de l&#8217;auteur : à la date de publication de cet article, la version 6.1 n&#8217;est toujours pas disponible. Une version Beta a été lancée le 14 octobre 2011 et selon la <a href="http://issues.liferay.com/browse/LPS#selectedTab=com.atlassian.jira.plugin.system.project%3Aroadmap-panel">roadmap Liferay</a>, une prochaine version Beta est attendue pour le 30 décembre 2011.</em></p>
<p>&nbsp;</p>
<p><span style="font-size: 15px;font-weight: bold">Ray is in trouble</span></p>
<p>Ray est la mascotte de la communauté Liferay. Il représente le développeur luttant sur un projet afin de le mener à bout. On peut suivre ses aventures sur<a href="http://www.liferay.com/ray"> liferay.com/ray</a>.</p>
<p><a href="http://blog.excilys.com/wp-content/uploads/2011/11/Capture.jpg"><img class="size-full wp-image-4033 alignnone" src="http://blog.excilys.com/wp-content/uploads/2011/11/Capture.jpg" alt="" width="137" height="98" /></a></p>
<p dir="ltr">Ray is in trouble, he needs some help !</p>
<p>&nbsp;</p>
<p><span style="font-size: 15px;font-weight: bold">Community Edition / Enterprise Edition</span></p>
</div>
<div style="text-align: justify">
<p dir="ltr">En 2008, Liferay a décidé de distribuer deux éditions différentes de leur produit : une édition communautaire (CE) gratuite et une édition entreprise (EE) payante.</p>
<p dir="ltr">James Falkner étant le Community Manager, il explique peu se soucier de la version Entreprise et préférer veiller au bon fonctionnement de l’édition Communautaire. Pour lui elle est la représentation de la communauté de Liferay. Son objectif est de rendre la version communautaire la plus performante possible même si cela amène une baisse des ventes de l’édition entreprise. Il est intéressé par l’open source et par les améliorations que cela amène. A l’heure actuelle on compte un million de déploiement de Liferay dans le monde dont une très grande majorité est issue de la version communautaire.</p>
<blockquote>
<p dir="ltr">“I could not care less whether there is not another Entreprise Edition subscription license sold ever again” (James Falkner)</p>
<p dir="ltr">&nbsp;</p>
</blockquote>
</div>
<div style="text-align: justify">
<h3>IRC</h3>
<p dir="ltr">James Falkner invite ceux qui ne connaissent pas ou très peu Liferay à se rendre sur <a href="http://www.liferay.org">liferay.org</a> afin d’en apprendre un peu plus.</p>
<p dir="ltr">Il invite également les personnes intéressées à se rendre sur le channel IRC de Liferay afin de prendre contact avec la communauté. Ce dernier est le meilleur moyen de participer à la vie de la communauté puisqu&#8217;il est toujours rempli d&#8217;au moins 25 personnes.</p>
<p dir="ltr">Pour James, l&#8217;IRC est l&#8217;esprit de l&#8217;open source et le réseau social par excellences.</p>
<p dir="ltr">Dans ce t’chat il n’y a pas de discussion type, mais on admettra trouver une petite majorité de sujets techniques, le tout dans une ambiance toujours sympathique.</p>
<p dir="ltr">Des annonces sont également diffusées par ce média.</p>
<p dir="ltr">James précise qu’il n’est pas nécessaire d’être un expert si on désire s&#8217;investir dans la communauté car il existe différents moyens de se rendre utile. Il cite comme exemple le travail de traduction, très utile, et  qui peut être effectué par n’importe qui durant son temps libre.</p>
<p><strong>IRC Server:</strong><br />
irc.freenode.com<br />
<strong>Channel:</strong><br />
#liferay</p>
</div>
<div style="text-align: justify">
<h3>Motivation, participation</h3>
<p dir="ltr">James nous raconte qu’une fois lors d’un <em>100 papercuts</em>, des goodies ont été envoyés aux trois meilleurs participants. Et, à leur grand étonnement, l’un des trois renvoya un e-mail expliquant que sa motivation n’était pas de recevoir des récompenses. Pour lui, seul la volonté de contribuer à une communauté le motivait.</p>
<p dir="ltr">Cette exemple nous montre qu’il n’y a pas que l&#8217;appât du gain qui motive les gens. Liferay possède une communauté qui est active et composée de membres voulant contribuer à cette dernière et sans forcément attendre quelque chose en retour, si ce n’est, peut être, la satisfaction d’avoir participé.</p>
<p>&nbsp;</p>
<p dir="ltr">Si vous voulez écouter le podcast c&#8217;est <a href="http://www.liferay.com/web/olaf.kock/blog/-/blogs/10504971">ici</a> que ça se passe !</p>
<p>&nbsp;</p>
</div>
<p style="text-align: justify">&nbsp;</p>
<p><!--[if IE]><iframe frameborder="0" allowTransparency="true" class="addtoany_special_service twitter_tweet" src="http://platform.twitter.com/widgets/tweet_button.html?url=http%3A%2F%2Fblog.excilys.com%2F2011%2F12%2F06%2Fradio-liferay-episode-1-james-falkner%2F&amp;counturl=http%3A%2F%2Fblog.excilys.com%2F2011%2F12%2F06%2Fradio-liferay-episode-1-james-falkner%2F&amp;count=horizontal&amp;text=Radio%20Liferay%20Episode%201%3A%20James%20Falkner" scrolling="no" style="border:none;overflow:hidden;width:130px;height:20px"></iframe><![endif]--><!--[if !IE]><!--><iframe class="addtoany_special_service twitter_tweet" src="http://platform.twitter.com/widgets/tweet_button.html?url=http%3A%2F%2Fblog.excilys.com%2F2011%2F12%2F06%2Fradio-liferay-episode-1-james-falkner%2F&amp;counturl=http%3A%2F%2Fblog.excilys.com%2F2011%2F12%2F06%2Fradio-liferay-episode-1-james-falkner%2F&amp;count=horizontal&amp;text=Radio%20Liferay%20Episode%201%3A%20James%20Falkner" scrolling="no" style="border:none;overflow:hidden;width:130px;height:20px"></iframe><!--<![endif]--><!--[if IE]><iframe frameborder="0" allowTransparency="true" class="addtoany_special_service google_plusone" src="https://plusone.google.com/u/0/_/%2B1/fastbutton?url=http%3A%2F%2Fblog.excilys.com%2F2011%2F12%2F06%2Fradio-liferay-episode-1-james-falkner%2F&amp;size=medium&amp;count=true" scrolling="no" style="border:none;overflow:hidden;width:90px;height:20px"></iframe><![endif]--><!--[if !IE]><!--><iframe class="addtoany_special_service google_plusone" src="https://plusone.google.com/u/0/_/%2B1/fastbutton?url=http%3A%2F%2Fblog.excilys.com%2F2011%2F12%2F06%2Fradio-liferay-episode-1-james-falkner%2F&amp;size=medium&amp;count=true" scrolling="no" style="border:none;overflow:hidden;width:90px;height:20px"></iframe><!--<![endif]--><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fblog.excilys.com%2F2011%2F12%2F06%2Fradio-liferay-episode-1-james-falkner%2F&amp;title=Radio%20Liferay%20Episode%201%3A%20James%20Falkner" id="wpa2a_4"><img src="http://blog.excilys.com/wp-content/plugins/add-to-any/share_save_120_16.png" width="120" height="16" alt="Share"/></a></p><img src="http://feeds.feedburner.com/~r/blogexcilyscom/~4/sbKj8O6ulak" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.excilys.com/2011/12/06/radio-liferay-episode-1-james-falkner/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://blog.excilys.com/2011/12/06/radio-liferay-episode-1-james-falkner/</feedburner:origLink></item>
		<item>
		<title>Construire sa propre plateforme de services</title>
		<link>http://feedproxy.google.com/~r/blogexcilyscom/~3/Ab0Rl1fShQw/</link>
		<comments>http://blog.excilys.com/2011/12/05/construire-sa-propre-plateforme-de-services/#comments</comments>
		<pubDate>Mon, 05 Dec 2011 12:07:38 +0000</pubDate>
		<dc:creator>Bastien JANSEN</dc:creator>
				<category><![CDATA[Non classé]]></category>
		<category><![CDATA[architecture]]></category>
		<category><![CDATA[dozer]]></category>
		<category><![CDATA[ESB]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[jersey]]></category>
		<category><![CDATA[mapping]]></category>
		<category><![CDATA[rest]]></category>
		<category><![CDATA[SOA]]></category>
		<category><![CDATA[spring]]></category>
		<category><![CDATA[web services]]></category>

		<guid isPermaLink="false">http://blog.excilys.com/?p=3604</guid>
		<description><![CDATA[Je vais vous décrire une petite plateforme de services que j&#8217;ai eu l&#8217;occasion de concevoir et de réaliser. Parce que tout a un début&#8230; Et en l’occurrence, le début est ici une besoin fonctionnel. Vous me direz tous que c&#8217;est normal, mais on a parfois tendance à oublier que la solution technique n&#8217;existe que pour [...]]]></description>
			<content:encoded><![CDATA[<p>Je vais vous décrire une petite plateforme de services que j&#8217;ai eu l&#8217;occasion de concevoir et de réaliser.<span id="more-3604"></span></p>
<h3>Parce que tout a un début&#8230;</h3>
<p>Et en l’occurrence, le début est ici une besoin fonctionnel. Vous me direz tous que c&#8217;est normal, mais on a parfois tendance à oublier que la solution technique n&#8217;existe que pour répondre à un besoin fonctionnel. <BR />Dans notre cas, nous avions besoin de mettre en place une plateforme permettant à des éléments d&#8217;un système informatique (que nous appellerons par la suite &#8220;consommateurs&#8221;) d&#8217;appeler des services, traitements ou ressources distantes (que nous appellerons systèmes externes). <BR />Cette plateforme doit présenter un nombre limité de points d&#8217;entrées (d&#8217;interfaces) à ses consommateurs. Chacun de ces points d&#8217;entrées doit faire correspondre une requête du consommateur à un appel de processus métier. Ces processus peuvent alors orchestrer des appels de services distants puis traiter et agréger les données retournées par ces appels. Les processus et services doivent être faciles à ajouter dans la plateforme et doivent avoir un couplage faible avec leurs interfaces. De plus, les systèmes externes sollicités par la plateforme exposent des services et interfaces qui leurs sont propres et qui ne doivent pas impacter le format des requêtes des consommateurs.</p>
<h3>Le tout, c&#8217;est d&#8217;avoir un plan</h3>
<p>Tenant compte de tous les éléments énoncés ci-dessus, j&#8217;ai modélisé (dans un premier temps) notre plateforme de la façon suivante: <BR /><BR /><br />
<a href="http://blog.excilys.com/wp-content/uploads/2011/10/schema_global1.png"><img src="http://blog.excilys.com/wp-content/uploads/2011/10/schema_global1-274x300.png" alt="" width="274" height="300" class="aligncenter size-medium wp-image-3734" /></a><br />
Jusque là, rien de transcendant me direz-vous. J&#8217;y ai représenté différents cas pouvant se produire :</p>
<ul>
<li>Nous avons une boite noire qui reçoit une requête de la part d&#8217;un consommateur X et appelle la &#8220;source de données&#8221; A.</li>
<li>La requête du consommateur Y donne lieu à des appels aux sources B et C. La plateforme héberge un processus qui orchestre les deux appels.</li>
<li>La requête du consommateur X ne déclenche aucun appel de service (on pourrait imaginer que les services correspondants n&#8217;ont pas été écrits).</li>
</ul>
<p></p>
<p>Par la suite, nous allons préciser peu à peu ce modèle pour faire apparaitre les différentes briques de notre plateforme et leurs responsabilités. Les fonctions à implémenter sont les suivantes :<br /><BR /></p>
<h6>Distribuer les appels de services</h6>
<p>Une requête provenant d&#8217;un consommateur doit déclencher le processus métier adéquat. C&#8217;est pour cela que la première étape du traitement de la requête sera son analyse par un <b>annuaire de services</b>. </p>
<h6>Traiter les processus métiers</h6>
<p>Une fois le bon <b>processus</b> identifié, celui-ci est appelé. Son rôle est de contacter les différents services nécessaires à son fonctionnement, organiser leurs appels, rassembler et agréger les résultats pour les retourner au consommateur.</p>
<h6>Traduire les paramètres</h6>
<p>Les systèmes externes auxquels les processus métiers font appel exposent leurs propres services et APIs. Les paramètres transmis dans la requête d&#8217;un consommateur ne doivent en aucun cas être contraints par ces interfaces. C&#8217;est pour cela qu&#8217;un composant appelé &#8220;<b>connecteur</b>&#8221; propre à chaque service externe aura la responsabilité de transcrire les paramètres dans un format attendu par le service. Les classes de ces paramètres (transmis à la plateforme) seront définies dans l&#8217;<b>API</b> de la plateforme.</p>
<h6>Contacter les services</h6>
<p>Les paramètres transcrits et intégrés dans la requête du service (sous forme d&#8217;objets JAXB, chaîne de caractères, etc&#8230;), le <b>connecteur</b> a la charge d&#8217;établir la connexion vers le système distant et d&#8217;en appeler le service ciblé.</p>
<h6>Traduire les réponses</h6>
<p>Comme pour les paramètres, nous allons devoir traiter les réponses des appels de services en les transcrivant dans des objets transverses. La transcription aura lieu dans le <b>connecteur</b> associé au service. Les classes d&#8217;objets transverses seront définies dans l&#8217;<b>API</b> de notre plateforme.<BR /><BR /></p>
<p>Nous avons maintenant un découpage plus précis de notre plateforme qui la fait ressembler à ceci :<BR /><BR /><br />
<a href="http://blog.excilys.com/wp-content/uploads/2011/10/schema_detaillé.png"><img src="http://blog.excilys.com/wp-content/uploads/2011/10/schema_detaillé-698x1024.png" alt="" width="698" height="1024" class="aligncenter size-large wp-image-3730" /></a></p>
<h3>J&#8217;aime quand un plan se déroule sans accroc.</h3>
<p><a href="http://blog.excilys.com/wp-content/uploads/2011/10/small_383151.jpg"><img src="http://blog.excilys.com/wp-content/uploads/2011/10/small_383151.jpg" alt="" width="214" height="215" class="alignright size-full wp-image-3758" /></a><br />
Maintenant que nous avons fait apparaître les différents composants de notre plateforme, nous devons choisir les solutions techniques qui vont intervenir dans leur réalisation. Différentes problématiques sont apparues :<BR /></p>
<h6>L&#8217;accès à la plateforme</h6>
<p>La plateforme doit être accessible d&#8217;une machine distante et  la solution la plus évidente est de lui faire exposer des web services. Dans notre cas, j&#8217;ai eu une préférence pour des services RESTful. Cette solution nous permettra de simplifier la détection du processus à appeler en tenant compte de la méthode HTTP comme premier filtrage de la requête. De plus, l&#8217;entête HTTP peut nous permettre de transmettre des meta-données nécessaires à la désérialisation des objets paramètres transmis (par exemple). Pour cela, nous avons choisi d&#8217;utiliser la librairie <a href="http://jersey.java.net/">Jersey</a> (implémentation de référence de la <a href="http://jcp.org/en/jsr/detail?id=311">JSR 311</a>). <BR />Parmi les formats de retour disponibles, nous avons retenu le JSON pour sa concision et sa légèreté. En effet, certains services devront retourner des quantités de données conséquentes qu&#8217;il est inutile d’alourdir avec des balises XML.</p>
<h6>Instanciation, initialisation et découplage</h6>
<p>Le découplage est ici essentiel puisque les composants tels que les connecteurs sont censés pouvoir être interchangés. Imaginons un processus de recherche de contenu qui interroge une GED via un connecteur conçu à cet effet. Si pour une raison quelconque on décidait de changer de GED, il faudrait ne réécrire que le composant connecteur.<BR /><br />
La plupart des objets de notre plateforme ne devront être instanciés qu&#8217;une seule fois. Je pense en particulier aux clients Jersey définis dans les couches DAO de certains connecteurs et dont l&#8217;instanciation coûte cher.<BR /><br />
Vous vous en doutez, la solution à ces deux problèmes est <a href="http://www.springsource.org/">Spring Framework</a> qui nous permet de contrôler l&#8217;instanciation de nos classes et d&#8217;assurer le découplage de nos composants.  Entre autres bienfaits, le découplage par Spring nous permettra aussi de faciliter la mise en place de tests unitaires (en pratiquant la programmation par interface et pourquoi pas le TDD). Nous verrons par la suite que Spring nous permettra de résoudre d&#8217;autre problèmes plus spécifiques.</p>
<h6>Implémenter l&#8217;annuaire de services</h6>
<p>Nous avons besoin d&#8217;une implémentation souple permettant l&#8217;ajout (fréquent) de processus métiers supplémentaires identifiés par des &#8220;clés&#8221;. Ces clés nous permettront de faire correspondre une requête de l&#8217;un de nos consommateurs à un processus métier à exécuter.<BR /><br />
La solution d&#8217;un bourrinisme achevé consisterait en un <del datetime="2011-10-10T22:41:53+00:00">immonde</del> gigantesque <em>switch</em>. Cette solution nous ferait modifier le code java et rajouter inutilement de la complexité cyclomatique à chaque ajout de nouveau processus métier dans notre plateforme. <BR />M&#8217;inspirant de <a href="http://blog.excilys.com/2010/06/25/de-switcher-nest-pas-jouer/">cet article</a>, j&#8217;ai eu l&#8217;idée de définir mes processus métiers dans Spring (jusque là c&#8217;était prévu) et de les regrouper dans une map instanciée et gérée par ce même Spring. Ainsi, en une poignée de lignes de codes, je récupère et exécute le processus correspondant à ma requête et ces lignes ne changeront jamais pourvu que les interfaces de mes processus soient bien pensées avec des paramètres génériques (merci java 5.0 ^_^°). Voici à quoi ressemble la configuration de tout ceci dans l&#8217;<i>applicationContext.xml</i>:</p>
<div class="codecolorer-container xml 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 /></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;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><br />
<span style="color: #009900;"> &nbsp; &nbsp;<span style="color: #000066;">xmlns:util</span>=<span style="color: #ff0000;">&quot;http://www.springframework.org/schema/util&quot;</span></span><br />
<span style="color: #009900;"> &nbsp; &nbsp;...</span><br />
<span style="color: #009900;"> &nbsp; &nbsp;<span style="color: #000066;">xsi:schemaLocation</span>=<span style="color: #ff0000;">&quot;... http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
<br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">&lt;!-- Import des applicationContexts des connecteurs --&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;import</span> <span style="color: #000066;">resource</span>=<span style="color: #ff0000;">&quot;classpath:applicationContext-customerConnector.xml&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;import</span> <span style="color: #000066;">resource</span>=<span style="color: #ff0000;">&quot;classpath:applicationContext-providererConnector.xml&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
&nbsp; &nbsp; ...<br />
<br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">&lt;!-- Point d'entree de la plateforme --&gt;</span><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;serviceEntryPoint&quot;</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;chemin.vers.ma.plateforme.ServiceEntryPoint&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;loadProcessMap&quot;</span> <span style="color: #000066;">ref</span>=<span style="color: #ff0000;">&quot;loadProcessMap&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;writeProcessMap&quot;</span> <span style="color: #000066;">ref</span>=<span style="color: #ff0000;">&quot;writeProcessMap&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;/bean<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">&lt;!-- map de processus de chargement/lecture de données--&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;util:map</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;loadProcessMap&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;entry</span> <span style="color: #000066;">key</span>=<span style="color: #ff0000;">&quot;loadCustomerData&quot;</span> &nbsp;<span style="color: #000066;">value-ref</span>=<span style="color: #ff0000;">&quot;customerLoader&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;entry</span> <span style="color: #000066;">key</span>=<span style="color: #ff0000;">&quot;loadProviderData&quot;</span> &nbsp;<span style="color: #000066;">value-ref</span>=<span style="color: #ff0000;">&quot;providerLoader&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; ...<br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/util:map<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">&lt;!-- map de processus d'écriture de données--&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;util:map</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;writeProcessMap&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;entry</span> <span style="color: #000066;">key</span>=<span style="color: #ff0000;">&quot;writeCustomerData&quot;</span> &nbsp;<span style="color: #000066;">value-ref</span>=<span style="color: #ff0000;">&quot;customerLoader&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; ...<br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/util:map<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">&lt;!-- beans de processus --&gt;</span> <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;customerLoader&quot;</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;chemin.vers.mes.processus.SimpleLoadProcess&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;connector&quot;</span> <span style="color: #000066;">ref</span>=<span style="color: #ff0000;">&quot;customerConnector&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;/bean<span style="color: #000000; font-weight: bold;">&gt;</span></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;providerLoader&quot;</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;chemin.vers.mes.processus.ProviderLoaderImpl&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;connector&quot;</span> <span style="color: #000066;">ref</span>=<span style="color: #ff0000;">&quot;providerConnector&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;/bean<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <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;customerWriter&quot;</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;chemin.vers.mes.processus.CustomerWriterImpl&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;connector&quot;</span> <span style="color: #000066;">ref</span>=<span style="color: #ff0000;">&quot;customerConnector&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;/bean<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; ...<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>
<p>Ainsi, l’implémentation du point d&#8217;entrée (avec Jersey) avec son annuaire de service est écrite de la façon suivante :</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 /></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;">chemin.vers.ma.plateforme</span><span style="color: #339933;">;</span><br />
<br />
@Path<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;/maPlateforme&quot;</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> ServiceEntryPoint<span style="color: #009900;">&#123;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> Map<span style="color: #339933;">&lt;</span><span style="color: #003399;">String</span>, LoadProcess<span style="color: #339933;">&lt;</span>Item, Param<span style="color: #339933;">&gt;&gt;</span> loadProcessMap<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> Map<span style="color: #339933;">&lt;</span><span style="color: #003399;">String</span>, WriteProcess<span style="color: #339933;">&lt;</span>Item<span style="color: #339933;">&gt;&gt;</span> writeProcessMap<span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; @POST<br />
&nbsp; &nbsp; @Consumes<span style="color: #009900;">&#40;</span>MediaType.<span style="color: #006633;">APPLICATION_XML</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; @Produces<span style="color: #009900;">&#40;</span>MediaType.<span style="color: #006633;">APPLICATION_JSON</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; @Path<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;{processusName}&quot;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> Item search<span style="color: #009900;">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; @PathParam<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;processName&quot;</span><span style="color: #009900;">&#41;</span> <span style="color: #003399;">String</span> processName, <br />
&nbsp; &nbsp; &nbsp; &nbsp; Param param<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; LoadProcess<span style="color: #339933;">&lt;</span>Item, Param<span style="color: #339933;">&gt;</span> process<span style="color: #339933;">=</span> loadProcessMap.<span style="color: #006633;">get</span><span style="color: #009900;">&#40;</span>processName<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">if</span><span style="color: #009900;">&#40;</span>process<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: #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;the [processName] path parameter does not match an existing process.&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; &nbsp; &nbsp; Item result <span style="color: #339933;">=</span> process.<span style="color: #006633;">load</span><span style="color: #009900;">&#40;</span>param<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> result<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: #000066; font-weight: bold;">void</span> setLoadProcessMap<span style="color: #009900;">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; Map<span style="color: #339933;">&lt;</span><span style="color: #003399;">String</span>, Processus<span style="color: #339933;">&lt;</span>Item, Param<span style="color: #339933;">&gt;&gt;</span> loadProcessMap<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">loadProcessMap</span><span style="color: #339933;">=</span> loadProcessMap<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: #000066; font-weight: bold;">void</span> setWriteProcessMap<span style="color: #009900;">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; Map<span style="color: #339933;">&lt;</span><span style="color: #003399;">String</span>, Processus<span style="color: #339933;">&lt;</span>Item<span style="color: #339933;">&gt;&gt;</span> writeProcessMap<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">writeProcessMap</span><span style="color: #339933;">=</span> writeProcessMap<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>
<p>Une implémentation possible de processus métier pourrait avoir la forme 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 />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 /></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;* Implementation d'un processus de lecture simple.<br />
&nbsp;*<br />
&nbsp;* @param &lt;I&gt; définit la classe de l'entité retournée.<br />
&nbsp;* @param &lt;P&gt; définit la classe du paramètre identifiant l'objet à retourner.<br />
&nbsp;*/</span><br />
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> SimpleLoadProcess<span style="color: #339933;">&lt;</span>I <span style="color: #000000; font-weight: bold;">extends</span> Item, P <span style="color: #000000; font-weight: bold;">extends</span> Param<span style="color: #339933;">&gt;</span> <span style="color: #000000; font-weight: bold;">implements</span> LoadProcess<span style="color: #339933;">&lt;</span>I, P<span style="color: #339933;">&gt;</span> <span style="color: #009900;">&#123;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">protected</span> &nbsp;LoaderConnector<span style="color: #339933;">&lt;</span>I, P<span style="color: #339933;">&gt;</span> connector<span style="color: #339933;">;</span><br />
&nbsp; <br />
&nbsp; &nbsp; @Override<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> I load<span style="color: #009900;">&#40;</span>P parametre<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; I result &nbsp;<span style="color: #339933;">=</span> connector.<span style="color: #006633;">loadObject</span><span style="color: #009900;">&#40;</span>parametre<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> result<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: #000066; font-weight: bold;">void</span> setConnector<span style="color: #009900;">&#40;</span>LoaderConnector<span style="color: #339933;">&lt;</span>I, P<span style="color: #339933;">&gt;</span> connector<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">connector</span> <span style="color: #339933;">=</span> connector<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>
<h6>Construction d&#8217;un connecteur</h6>
<p>Compte tenu du rôle joué par un connecteur, sa structure sera presque toujours articulée en 3 parties : </p>
<ul>
<li>Un <b>interpréteur de critères</b> qui transcrit les entrées du service en un format que pourra traiter le service distant.</li>
<li>Un <b>DAO</b> qui gère la connexion au service et l&#8217;envoi de la requête.</li>
<li>Un <b>constructeur de réponses</b> qui initialise une structure d&#8217;objets à partir de la réponse du service appelé.</li>
</ul>
<p>Regardons par exemple le fichier <i>applicationContext-customerConnector.xml</i>:</p>
<div class="codecolorer-container xml 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="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">&lt;!-- Connecteur --&gt;</span><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;customerConnector&quot;</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;chemin.vers.CustomerConnectorImpl&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;idTranslator&quot;</span> <span style="color: #000066;">ref</span>=<span style="color: #ff0000;">&quot;customerIdTranslator&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;customerTranslator&quot;</span> <span style="color: #000066;">ref</span>=<span style="color: #ff0000;">&quot;customerTranslator&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;dao&quot;</span> <span style="color: #000066;">ref</span>=<span style="color: #ff0000;">&quot;customerDao&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;responseBuilder&quot;</span> <span style="color: #000066;">ref</span>=<span style="color: #ff0000;">&quot;customerResponseBuilder&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;/bean<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp;<br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">&lt;!-- DAO--&gt;</span><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;customerDao&quot;</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;chemin.vers.CustomerDao&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;baseUrl&quot;</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;${customer.service.url.base}&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;login&quot;</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;${customer.service.login}&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;password&quot;</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;${customer.service.password}&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;/bean<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp;<br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">&lt;!-- interpeteurs de parametres --&gt;</span><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;customerIdTranslator&quot;</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;chemin.vers.CustomerIdTranslator&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;bean</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;customerTranslator&quot;</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;chemin.vers.CustomerTranslator&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
&nbsp; <br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">&lt;!-- constructeur de reponse --&gt;</span><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;customerResponseBuilder&quot;</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;chemin.vers.CustomerResponseBuilder&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span></div></td></tr></tbody></table></div>
<p>Avec pour implémentation du bean <i>customerConnector</i> :</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 />40<br />41<br />42<br />43<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> CustomerConnectorImpl <span style="color: #000000; font-weight: bold;">implements</span> LoaderConnector<span style="color: #339933;">&lt;</span>Customer, CustomerId<span style="color: #339933;">&gt;</span>, WriterConnector<span style="color: #339933;">&lt;</span>Customer<span style="color: #339933;">&gt;</span> <span style="color: #009900;">&#123;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> ParamTranslator<span style="color: #339933;">&lt;</span>CustomerId, CustomerIdDTO<span style="color: #339933;">&gt;</span> idTranslator<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> ParamTranslator<span style="color: #339933;">&lt;</span>Customer, CustomerDTO<span style="color: #339933;">&gt;</span> customerTranslator<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> CustomerDaoImpl customerDao<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> ResponseBuilder<span style="color: #339933;">&lt;</span>CustomerDTO, Customer<span style="color: #339933;">&gt;</span> responseBuilder<span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #008000; font-style: italic; font-weight: bold;">/**<br />
&nbsp; &nbsp; &nbsp;*@see chemin.vers.LoaderConnector.loadObject()<br />
&nbsp; &nbsp; &nbsp;*/</span><br />
&nbsp; &nbsp; @Override<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> Customer loadObject<span style="color: #009900;">&#40;</span>CustomerId id<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; CustomerIdDTO idDTO <span style="color: #339933;">=</span> idTranslator.<span style="color: #006633;">translate</span><span style="color: #009900;">&#40;</span>id<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; CustomerDTO customerDTO <span style="color: #339933;">=</span> customerDao.<span style="color: #006633;">loadObject</span><span style="color: #009900;">&#40;</span>idDTO<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> responseBuilder.<span style="color: #006633;">translate</span><span style="color: #009900;">&#40;</span>customerDTO<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
<br />
&nbsp; &nbsp; <span style="color: #008000; font-style: italic; font-weight: bold;">/**<br />
&nbsp; &nbsp; &nbsp; *@see chemin.vers.WriterConnector.writeObject()<br />
&nbsp; &nbsp; &nbsp; */</span><br />
&nbsp; &nbsp; &nbsp;@Override<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> writeObject<span style="color: #009900;">&#40;</span>Customer entite<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; CustomerDTO customerDTO <span style="color: #339933;">=</span> customerTranslator.<span style="color: #006633;">translate</span><span style="color: #009900;">&#40;</span>entite<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; customerDao.<span style="color: #006633;">writeObject</span><span style="color: #009900;">&#40;</span>customerDTO<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;">public</span> <span style="color: #000066; font-weight: bold;">void</span> setIdTranslator<span style="color: #009900;">&#40;</span>ParamTranslator<span style="color: #339933;">&lt;</span>CustomerId, CustomerIdDTO<span style="color: #339933;">&gt;</span> idTranslator<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">idTranslator</span> <span style="color: #339933;">=</span> idTranslator<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: #000066; font-weight: bold;">void</span> setCustomerTranslator<span style="color: #009900;">&#40;</span>ParamTranslator<span style="color: #339933;">&lt;</span>Customer, CustomerDTO<span style="color: #339933;">&gt;</span> customerTranslator<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">customerTranslator</span><span style="color: #339933;">=</span>customerTranslator<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: #000066; font-weight: bold;">void</span> setCustomerDao<span style="color: #009900;">&#40;</span>CustomerDaoImpl customerDao<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">customerDao</span><span style="color: #339933;">=</span>customerDao<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: #000066; font-weight: bold;">void</span> setResponseBuilder<span style="color: #009900;">&#40;</span>ResponseBuilder<span style="color: #339933;">&lt;</span>CustomerDTO, Customer<span style="color: #339933;">&gt;</span> responseBuilder<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">responseBuilder</span><span style="color: #339933;">=</span>responseBuilder<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>
<h6>La transcription des paramètres et des réponses</h6>
<p>Là encore la transcription des POJOs de l&#8217;API de la plateforme en POJOs  de l&#8217;API d&#8217;un service externe peut être faite de façon peu subtile :</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">pojo1.<span style="color: #006633;">setX</span><span style="color: #009900;">&#40;</span>pojo2.<span style="color: #006633;">getX</span><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>
<p>Cette solution serait à la fois fastidieuse à écrire et à maintenir. C&#8217;est pour cela que nous préférons utiliser <a href="http://dozer.sourceforge.net/">Dozer</a> qui a le bon goût de s&#8217;intégrer simplement dans la configuration Spring de notre connecteur:</p>
<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 /></div></td><td><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&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;monMapper&quot;</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;org.dozer.DozerBeanMapper&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;mappingFiles&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;list<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;value<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>dozer.xml<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/value<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;/list<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 />
<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;customerTranslator&quot;</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;chemin.vers.CustomerTranslator&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;dozerMapper&quot;</span> <span style="color: #000066;">ref</span>=<span style="color: #ff0000;">&quot;monMapper&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;/bean<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></td></tr></tbody></table></div>
<p>Ce qui nous donne l&#8217;implémentation 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 />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: #000000; font-weight: bold;">class</span> CustomerTranslator <span style="color: #000000; font-weight: bold;">implements</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; ParamTranslator<span style="color: #339933;">&lt;</span>Customer, CustomerDTO<span style="color: #339933;">&gt;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> DozerBeanMapper dozerMapper<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; @Override<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> CustomerDTO translate<span style="color: #009900;">&#40;</span>Customer customer<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; CustomerDTO dto<span style="color: #339933;">=</span> dozerMapper.<span style="color: #006633;">map</span><span style="color: #009900;">&#40;</span>customer, CustomerDTO.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> dto<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: #000066; font-weight: bold;">void</span> setDozerMapper<span style="color: #009900;">&#40;</span>DozerBeanMapper dozerMapper<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">dozerMapper</span> <span style="color: #339933;">=</span> dozerMapper<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>
<p><H3>En conclusion</H3><br />
La flexibilité et l&#8217;ouverture de Spring nous permettent d&#8217;envisager les améliorations suivantes : </p>
<ul>
<li>Tissage d&#8217;aspects à la compilation (par exemple pour générer des logs de statistiques).</li>
<li>Intégration de frameworks, ORM et webservices.</li>
</ul>
<p>Ceci conclut cet article. Vous voilà maintenant prêts à monter votre propre ESB maison.</p>
<p><!--[if IE]><iframe frameborder="0" allowTransparency="true" class="addtoany_special_service twitter_tweet" src="http://platform.twitter.com/widgets/tweet_button.html?url=http%3A%2F%2Fblog.excilys.com%2F2011%2F12%2F05%2Fconstruire-sa-propre-plateforme-de-services%2F&amp;counturl=http%3A%2F%2Fblog.excilys.com%2F2011%2F12%2F05%2Fconstruire-sa-propre-plateforme-de-services%2F&amp;count=horizontal&amp;text=Construire%20sa%20propre%20plateforme%20de%20services" scrolling="no" style="border:none;overflow:hidden;width:130px;height:20px"></iframe><![endif]--><!--[if !IE]><!--><iframe class="addtoany_special_service twitter_tweet" src="http://platform.twitter.com/widgets/tweet_button.html?url=http%3A%2F%2Fblog.excilys.com%2F2011%2F12%2F05%2Fconstruire-sa-propre-plateforme-de-services%2F&amp;counturl=http%3A%2F%2Fblog.excilys.com%2F2011%2F12%2F05%2Fconstruire-sa-propre-plateforme-de-services%2F&amp;count=horizontal&amp;text=Construire%20sa%20propre%20plateforme%20de%20services" scrolling="no" style="border:none;overflow:hidden;width:130px;height:20px"></iframe><!--<![endif]--><!--[if IE]><iframe frameborder="0" allowTransparency="true" class="addtoany_special_service google_plusone" src="https://plusone.google.com/u/0/_/%2B1/fastbutton?url=http%3A%2F%2Fblog.excilys.com%2F2011%2F12%2F05%2Fconstruire-sa-propre-plateforme-de-services%2F&amp;size=medium&amp;count=true" scrolling="no" style="border:none;overflow:hidden;width:90px;height:20px"></iframe><![endif]--><!--[if !IE]><!--><iframe class="addtoany_special_service google_plusone" src="https://plusone.google.com/u/0/_/%2B1/fastbutton?url=http%3A%2F%2Fblog.excilys.com%2F2011%2F12%2F05%2Fconstruire-sa-propre-plateforme-de-services%2F&amp;size=medium&amp;count=true" scrolling="no" style="border:none;overflow:hidden;width:90px;height:20px"></iframe><!--<![endif]--><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fblog.excilys.com%2F2011%2F12%2F05%2Fconstruire-sa-propre-plateforme-de-services%2F&amp;title=Construire%20sa%20propre%20plateforme%20de%20services" id="wpa2a_6"><img src="http://blog.excilys.com/wp-content/plugins/add-to-any/share_save_120_16.png" width="120" height="16" alt="Share"/></a></p><img src="http://feeds.feedburner.com/~r/blogexcilyscom/~4/Ab0Rl1fShQw" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.excilys.com/2011/12/05/construire-sa-propre-plateforme-de-services/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://blog.excilys.com/2011/12/05/construire-sa-propre-plateforme-de-services/</feedburner:origLink></item>
		<item>
		<title>SAML 2 et Liferay – partie 3</title>
		<link>http://feedproxy.google.com/~r/blogexcilyscom/~3/QoJ2BdDs-3A/</link>
		<comments>http://blog.excilys.com/2011/11/17/saml-2-et-liferay-partie-3/#comments</comments>
		<pubDate>Thu, 17 Nov 2011 11:08:06 +0000</pubDate>
		<dc:creator>Denis VAUMORON</dc:creator>
				<category><![CDATA[Non classé]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[Liferay]]></category>
		<category><![CDATA[Liferay Portal]]></category>
		<category><![CDATA[Portal]]></category>
		<category><![CDATA[SAML]]></category>

		<guid isPermaLink="false">http://blog.excilys.com/?p=3632</guid>
		<description><![CDATA[Dans le précédent épisode article (oui, je sais que les meilleures blagues sont les plus courtes, mais non, je n’ai pas l’intention d’arrêter de faire cette blague pourrie, habituez vous), nous avons vu comment envoyer un message en suivant le HTTP Redirect Binding, maintenant que nous avons notre bouteille, il va nous falloir prendre notre [...]]]></description>
			<content:encoded><![CDATA[<p>Dans le précédent <del>épisode</del> <a title="SAML 2 et Liferay – partie 2" href="http://blog.excilys.com/2011/10/04/saml-2-et-liferay-partie-2/">article</a> (oui, je sais que les meilleures blagues sont les plus courtes, mais non, je n’ai pas l’intention d’arrêter de faire cette blague pourrie, habituez vous), nous avons vu comment envoyer un message en suivant le HTTP Redirect Binding, maintenant que nous avons notre bouteille, il va nous falloir prendre notre plus beau parchemin et écrire ce message <del>de détresse</del>.<br />
<span id="more-3632"></span></p>
<h3>Tous les cris, les S O S…</h3>
<p>Nous voulons envoyer une demande d’authentification, en voici un exemple :</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;samlp:AuthnRequest</span></span><br />
<span style="color: #009900;"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #000066;">xmlns:samlp</span>=<span style="color: #ff0000;">&quot;urn:oasis:names:tc:SAML:2.0:protocol&quot;</span></span><br />
<span style="color: #009900;"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #000066;">xmlns:saml</span>=<span style="color: #ff0000;">&quot;urn:oasis:names:tc:SAML:2.0:assertion&quot;</span></span><br />
<span style="color: #009900;"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #000066;">ID</span>=<span style="color: #ff0000;">&quot;sk3k82Vt5uJamRNo1DgtgoKikrLH&quot;</span></span><br />
<span style="color: #009900;"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #000066;">Version</span>=<span style="color: #ff0000;">&quot;2.0&quot;</span></span><br />
<span style="color: #009900;"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #000066;">IssueInstant</span>=<span style="color: #ff0000;">&quot;2011-07-07T20:46:09Z&quot;</span></span><br />
<span style="color: #009900;"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #000066;">IsPassive</span>=<span style="color: #ff0000;">&quot;true&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;saml:Issuer<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>http://blog.excilys.com<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/saml:Issuer<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/samlp:AuthnRequest<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></td></tr></tbody></table></div>
</pre>
<p>Notre cas est simple, si nous excluons  le formalisme (notamment les déclarations d’espace de noms), nous n’envoyons que quatre informations :</p>
<ul>
<li>ID, qui permet d’identifier le message</li>
<li>IssueInstant, la date de génération du message</li>
<li>IsPassive, optionnel, permet de demander que le fournisseur d’identité réponde sans interagir avec l’utilisateur</li>
<li>Issuer, qui permet d’identifier l’expéditeur du message</li>
</ul>
<p>Et là ? Révélations ! IsPassive résout notre problème (mais si, vous vous souvenez…), lorsqu’un utilisateur arrivera sur le portail, nous ferons systématiquement la demande d’authentification. Pour savoir si l&#8217;utilisateur tente de se connecter, il nous suffira de tester si l’url contient le fameux « /portal/login », dans ce cas, il ne faut pas envoyer IsPassive à true, ainsi le fournisseur d&#8217;identité affichera sa page de connexion. Cependant, il ne faut pas oublier de placer un indicateur en session pour éviter que les deux serveurs ne se mettent à jouer au ping pong (En effet, si l’utilisateur n’est pas déjà connecté sur l’IdP, celui-ci renverra une réponse négative (pas de cookie) sans proposer de page de connexion (à cause du isPassive) , et le SP renverra une demande&#8230;). Pour générer le message, nous allons profiter de l’API XML intégrée dans Liferay (en fait, c’est une encapsulation de dom4j) :</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 />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 /></div></td><td><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #003399;">String</span> generateAuthnRequest<span style="color: #009900;">&#40;</span><br />
                        HttpServletRequest request, <span style="color: #003399;">String</span> loginUrl,<br />
                        <span style="color: #003399;">String</span> samlEntityId, <span style="color: #003399;">String</span> relayState, <span style="color: #003399;">String</span> signAlg,<br />
                        <span style="color: #003399;">Boolean</span> isPassive<span style="color: #009900;">&#41;</span><br />
                <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">Exception</span> <span style="color: #009900;">&#123;</span><br />
<br />
                <span style="color: #003399;">String</span> messageID <span style="color: #339933;">=</span> generateMessageID<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
                <span style="color: #666666; font-style: italic;">// on stocke l'id pour tester la correspondance de la réponse</span><br />
<br />
                request.<span style="color: #006633;">getSession</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">setAttribute</span><span style="color: #009900;">&#40;</span><br />
                        SAMLConstants.<span style="color: #006633;">MESSAGE_ID</span>, messageID<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
                <span style="color: #003399;">Document</span> document <span style="color: #339933;">=</span> SAXReaderUtil.<span style="color: #006633;">createDocument</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
                Namespace samlp <span style="color: #339933;">=</span> SAXReaderUtil.<span style="color: #006633;">createNamespace</span><span style="color: #009900;">&#40;</span><br />
                        SAMLConstants.<span style="color: #006633;">SAMLP</span>, SAMLConstants.<span style="color: #006633;">PROTOCOL_NAMESPACE</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
                Namespace saml <span style="color: #339933;">=</span> SAXReaderUtil.<span style="color: #006633;">createNamespace</span><span style="color: #009900;">&#40;</span><br />
                        SAMLConstants.<span style="color: #006633;">SAML</span>, SAMLConstants.<span style="color: #006633;">ASSERTION_NAMESPACE</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
                <span style="color: #003399;">Element</span> authnRequest <span style="color: #339933;">=</span> document.<span style="color: #006633;">addElement</span><span style="color: #009900;">&#40;</span><br />
                        SAXReaderUtil.<span style="color: #006633;">createQName</span><span style="color: #009900;">&#40;</span><br />
                        SAMLConstants.<span style="color: #006633;">AUTHN_REQUEST</span>, samlp<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
                authnRequest.<span style="color: #006633;">add</span><span style="color: #009900;">&#40;</span>samlp<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
                authnRequest.<span style="color: #006633;">add</span><span style="color: #009900;">&#40;</span>saml<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
                authnRequest.<span style="color: #006633;">addAttribute</span><span style="color: #009900;">&#40;</span>SAMLConstants.<span style="color: #006633;">ID</span>, messageID<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
                authnRequest.<span style="color: #006633;">addAttribute</span><span style="color: #009900;">&#40;</span><br />
                        SAMLConstants.<span style="color: #006633;">VERSION</span>, SAMLConstants.<span style="color: #006633;">VERSION_2_0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
                authnRequest.<span style="color: #006633;">addAttribute</span><span style="color: #009900;">&#40;</span><br />
                        SAMLConstants.<span style="color: #006633;">ISSUE_INSTANT</span>, formatDate<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">Date</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
                authnRequest.<span style="color: #006633;">addAttribute</span><span style="color: #009900;">&#40;</span>SAMLConstants.<span style="color: #006633;">DESTINATION</span>, loginUrl<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
                <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>isPassive <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 />
                        authnRequest.<span style="color: #006633;">addAttribute</span><span style="color: #009900;">&#40;</span><br />
                                SAMLConstants.<span style="color: #006633;">IS_PASSIVE</span>, isPassive.<span style="color: #006633;">toString</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 />
                <span style="color: #009900;">&#125;</span><br />
<br />
                <span style="color: #003399;">Element</span> issuer <span style="color: #339933;">=</span> authnRequest.<span style="color: #006633;">addElement</span><span style="color: #009900;">&#40;</span><br />
                        SAXReaderUtil.<span style="color: #006633;">createQName</span><span style="color: #009900;">&#40;</span>SAMLConstants.<span style="color: #006633;">ISSUER</span>, saml<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
                issuer.<span style="color: #006633;">setText</span><span style="color: #009900;">&#40;</span>samlEntityId<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
                <span style="color: #003399;">String</span> xmlString <span style="color: #339933;">=</span> document.<span style="color: #006633;">asXML</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
                <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>_log.<span style="color: #006633;">isDebugEnabled</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
                        _log.<span style="color: #006633;">debug</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;send : &quot;</span> <span style="color: #339933;">+</span> xmlString<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;">return</span> getHTTPRedirectBindingUrl<span style="color: #009900;">&#40;</span><br />
                        loginUrl, <span style="color: #000066; font-weight: bold;">true</span>, xmlString, relayState, signAlg<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: #000000; font-weight: bold;">static</span> <span style="color: #003399;">String</span> generateMessageID<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
                <span style="color: #666666; font-style: italic;">// l'id doit être unique, dans le cas d'une technique</span><br />
                <span style="color: #666666; font-style: italic;">// aléatoire, le standard recommande une longueur de plus de</span><br />
                <span style="color: #666666; font-style: italic;">// 160 bit (moins de 2^-160 chances de collision)</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// l'encodage en base 64 rallonge d'1/3, en octets pleins, la longueur supérieure la plus</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// approchante est 21 (21*8=168 &gt; 160), on aura donc en sortie un id sur 28 caractères.</span><br />
                <span style="color: #000066; font-weight: bold;">byte</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> randomBytes <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #000066; font-weight: bold;">byte</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">21</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
                _random.<span style="color: #006633;">nextBytes</span><span style="color: #009900;">&#40;</span>randomBytes<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
                <span style="color: #000000; font-weight: bold;">return</span> Base64.<span style="color: #006633;">encode</span><span style="color: #009900;">&#40;</span>randomBytes<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: #000000; font-weight: bold;">static</span> <span style="color: #003399;">String</span> formatDate<span style="color: #009900;">&#40;</span><span style="color: #003399;">Date</span> date<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
                <span style="color: #000000; font-weight: bold;">return</span> _getDateFormat<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">format</span><span style="color: #009900;">&#40;</span>date<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;">private</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #003399;">DateFormat</span> _getDateFormat<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
                <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">SimpleDateFormat</span><span style="color: #009900;">&#40;</span>_DATE_PATTERN<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;">private</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">String</span> _DATE_PATTERN <span style="color: #339933;">=</span><br />
                <span style="color: #0000ff;">&quot;yyyy-MM-dd'T'HH:mm:ss'Z'&quot;</span><span style="color: #339933;">;</span><br />
<br />
        <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">static</span> Log _log <span style="color: #339933;">=</span> LogFactoryUtil.<span style="color: #006633;">getLog</span><span style="color: #009900;">&#40;</span>SAMLUtil.<span style="color: #000000; font-weight: bold;">class</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: #000000; font-weight: bold;">static</span> <span style="color: #003399;">Random</span> _random <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">Random</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></td></tr></tbody></table></div>
</pre>
<h3>Une boite aux lettres</h3>
<p>Si nous reprenons notre descriptif de l’échange (ça vous avait presque manqué, non ?) :</p>
<p><a href="http://blog.excilys.com/wp-content/uploads/2011/09/diagrammeSAML.jpg"><img class="alignnone size-full wp-image-3572" src="http://blog.excilys.com/wp-content/uploads/2011/09/diagrammeSAML.jpg" alt="Diagramme de séquence du SSO en SAML" width="570" height="435" /></a></p>
<p>Nous avons envoyé la &lt;AuthnRequest&gt;, le fournisseur d’identité va s’occuper de l’étape 3) d’identification de l’utilisateur, puis ensuite à l’étape 4), il va nous renvoyer une &lt;Response&gt;, celle-ci pouvant comporter de nombreuses informations sur l’utilisateur. Pour pouvoir recevoir cette réponse, nous allons mettre en place un endpoint de type assertion consumer service supportant le HTTP Post Binding (étant donné que le standard spécifie que l’on ne doit pas utiliser le HTTP Redirect Binding), autrement dit une url qui va pouvoir recevoir un paramètre Response, celui-ci étant encodé en base64 (et non, pas de DEFLATE dans ce binding). Pour cela, il faut indiquer à Liferay de reconnaitre l’url en ajoutant celle-ci à la propriété virtual.hosts.ignore.paths (situé dans portal.properties) pour éviter une redirection qui nous ferait perdre les paramètres du post (lorsque Liferay ne trouve pas de page associée à l’adresse par son mécanisme de « friendly URL », il redirige vers la page par défaut).</p>
<p>A ce moment, l’utilisateur n’étant pas encore authentifié par Liferay, le système d’AutoLogin va se déclencher, ce qui va nous permettre de simplement tester la présence du paramètre Response au niveau de notre SAMLAutoLogin :</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 /></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;">static</span> <span style="color: #000066; font-weight: bold;">boolean</span> isAuthenticated<span style="color: #009900;">&#40;</span><br />
                HttpServletRequest request, <span style="color: #003399;">String</span> loginUrl,<br />
                <span style="color: #003399;">String</span> samlEntityId, <span style="color: #003399;">String</span> samlIdentityProviderId,<br />
                <span style="color: #003399;">String</span> signAlg, HttpServletResponse response<span style="color: #009900;">&#41;</span><br />
        <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">Exception</span> <span style="color: #009900;">&#123;</span><br />
<br />
        <span style="color: #003399;">String</span> samlResponseParameter <span style="color: #339933;">=</span><br />
                request.<span style="color: #006633;">getParameter</span><span style="color: #009900;">&#40;</span>SAMLConstants.<span style="color: #006633;">SAML_RESPONSE</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
        <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>samlResponseParameter <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 />
                <span style="color: #003399;">String</span> samlResponse <span style="color: #339933;">=</span> getSamlFromHTTPPostBindingParameter<span style="color: #009900;">&#40;</span><br />
                        samlResponseParameter<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
                <span style="color: #666666; font-style: italic;">// TODO lecture de la réponse</span><br />
        <span style="color: #009900;">&#125;</span><br />
        <span style="color: #000000; font-weight: bold;">else</span> <span style="color: #009900;">&#123;</span><br />
                sendAuthnRequest<span style="color: #009900;">&#40;</span><br />
                        request, response, samlEntityId, loginUrl, signAlg<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;">return</span> <span style="color: #000066; font-weight: bold;">false</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div>
</pre>
<h3>C’est fini pour aujourd’hui</h3>
<p>Nous sommes désormais capable d’envoyer une demande d’authentification, et nous avons mis en place un endpoint pour recevoir la réponse, dans le prochain article nous analyserons la réponse afin de connecter l’utilisateur à Liferay (ou pas).</p>
<p>A bientôt pour de nouvelles aventures sur le blog Excilys…</p>
<p>&nbsp;</p>
<p><!--[if IE]><iframe frameborder="0" allowTransparency="true" class="addtoany_special_service twitter_tweet" src="http://platform.twitter.com/widgets/tweet_button.html?url=http%3A%2F%2Fblog.excilys.com%2F2011%2F11%2F17%2Fsaml-2-et-liferay-partie-3%2F&amp;counturl=http%3A%2F%2Fblog.excilys.com%2F2011%2F11%2F17%2Fsaml-2-et-liferay-partie-3%2F&amp;count=horizontal&amp;text=SAML%202%20et%20Liferay%20%26%238211%3B%20partie%203" scrolling="no" style="border:none;overflow:hidden;width:130px;height:20px"></iframe><![endif]--><!--[if !IE]><!--><iframe class="addtoany_special_service twitter_tweet" src="http://platform.twitter.com/widgets/tweet_button.html?url=http%3A%2F%2Fblog.excilys.com%2F2011%2F11%2F17%2Fsaml-2-et-liferay-partie-3%2F&amp;counturl=http%3A%2F%2Fblog.excilys.com%2F2011%2F11%2F17%2Fsaml-2-et-liferay-partie-3%2F&amp;count=horizontal&amp;text=SAML%202%20et%20Liferay%20%26%238211%3B%20partie%203" scrolling="no" style="border:none;overflow:hidden;width:130px;height:20px"></iframe><!--<![endif]--><!--[if IE]><iframe frameborder="0" allowTransparency="true" class="addtoany_special_service google_plusone" src="https://plusone.google.com/u/0/_/%2B1/fastbutton?url=http%3A%2F%2Fblog.excilys.com%2F2011%2F11%2F17%2Fsaml-2-et-liferay-partie-3%2F&amp;size=medium&amp;count=true" scrolling="no" style="border:none;overflow:hidden;width:90px;height:20px"></iframe><![endif]--><!--[if !IE]><!--><iframe class="addtoany_special_service google_plusone" src="https://plusone.google.com/u/0/_/%2B1/fastbutton?url=http%3A%2F%2Fblog.excilys.com%2F2011%2F11%2F17%2Fsaml-2-et-liferay-partie-3%2F&amp;size=medium&amp;count=true" scrolling="no" style="border:none;overflow:hidden;width:90px;height:20px"></iframe><!--<![endif]--><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fblog.excilys.com%2F2011%2F11%2F17%2Fsaml-2-et-liferay-partie-3%2F&amp;title=SAML%202%20et%20Liferay%20%26%238211%3B%20partie%203" id="wpa2a_8"><img src="http://blog.excilys.com/wp-content/plugins/add-to-any/share_save_120_16.png" width="120" height="16" alt="Share"/></a></p><img src="http://feeds.feedburner.com/~r/blogexcilyscom/~4/QoJ2BdDs-3A" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.excilys.com/2011/11/17/saml-2-et-liferay-partie-3/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://blog.excilys.com/2011/11/17/saml-2-et-liferay-partie-3/</feedburner:origLink></item>
		<item>
		<title>Radio Liferay – Episode 3 : Nate Cavanaugh présente AlloyUI</title>
		<link>http://feedproxy.google.com/~r/blogexcilyscom/~3/t4S3lLGCx-o/</link>
		<comments>http://blog.excilys.com/2011/11/10/radio-liferay-episode-3-nate-cavanaugh-presente-alloyui/#comments</comments>
		<pubDate>Thu, 10 Nov 2011 16:10:42 +0000</pubDate>
		<dc:creator>Valentine VAUGELADE</dc:creator>
				<category><![CDATA[Non classé]]></category>
		<category><![CDATA[Liferay Portal]]></category>
		<category><![CDATA[Podcast]]></category>
		<category><![CDATA[Radio Liferay]]></category>

		<guid isPermaLink="false">http://blog.excilys.com/?p=4005</guid>
		<description><![CDATA[Cet article est un résumé du troisième épisode de radio Liferay relatant la conversation entre Olaf Kock, consultant sénior chez Liferay, et Nate Cavanaugh, directeur du service en charge de l&#8217;interface utilisateur. Nate Cavanaugh et Liferay Nate Cavanaugh a commencé sa carrière professionnelle en tant que designer graphique. Il est à l&#8217;origine du développement de [...]]]></description>
			<content:encoded><![CDATA[<p>Cet article est un résumé du troisième épisode de radio Liferay relatant la conversation entre Olaf Kock, consultant sénior chez Liferay, et Nate Cavanaugh, directeur du service en charge de l&#8217;interface utilisateur.</p>
<p><span id="more-4005"></span></p>
<p><span style="color: #666699"><strong>Nate Cavanaugh et Liferay</strong></span></p>
<p>Nate Cavanaugh a commencé sa carrière professionnelle en tant que designer graphique. Il est à l&#8217;origine du développement de nombreux sites internet mais a aussi travaillé à la construction de son propre CMS (Content Management System). Sa rencontre avec Michael Young, directeur technique de Liferay, lui a permis d&#8217;intégrer le projet Liferay. Ses premiers pas sur le projet ont consisté à repenser l&#8217;architecture du système mis en place pour les thèmes.</p>
<p>&nbsp;</p>
<p><span style="color: #666699"><strong><span>De JQuery à AlloyUI</span></strong></span></p>
<p>Liferay est le premier portail à avoir proposé le &#8220;drag and drop&#8221; pour ses portlets. Dans la version 4.3, l&#8217;implémentation de cette fonctionnalité a été repensée pour utiliser JQuery. Suite à cela, JQuery est devenu le framework standard de l&#8217;interface utilisateur dans la version 5.7.</p>
<p>Mais la version 6 de Liferay a apporté un énorme changement : l&#8217;interface utilisateur n&#8217;est plus gérée par JQuery mais par AlloyUI ! Pourquoi ce choix ? Parce que développeurs et clients étaient trop souvent confrontés à des problèmes avec JQuery. En effet, l&#8217;intégration de JQuery à Liferay est gérée par des plugins. A chaque mise à jour de JQuery les développeurs devaient résoudre des bugs avec les plugins mais devaient aussi pouvoir répondre des bugs rencontrés par les utilisateurs de Liferay. Pour pouvoir sécuriser les clients utilisant la version entreprise, mais aussi pour faciliter le développement, il était nécessaire d&#8217;utiliser un framework sur lequel ils auraient plus de contrôle. Toutes ces constatations ont mené à l&#8217;abandon de JQuery.</p>
<p>Il a fallu alors se pencher sur l&#8217;adoption d&#8217;un autre framework. Les membres de Liferay voulaient un framework plus flexible et plus fiable que JQuery pour l&#8217;interface utilisateur. Ils ont donc fait le tour des frameworks javascript disponibles sur le marché, et deux d&#8217;entre eux ont spécifiquement retenu leur attention : <a href="http://dojotoolkit.org/">Dojo</a> et <a href="http://developer.yahoo.com/yui/">YUI</a> (de Yahoo). Les tests en interne de Dojo n&#8217;étant pas concluants, YUI a été retenu semblant plus facile d&#8217;utilisation et mieux adapté à leur besoin.</p>
<p>Si YUI a été retenu, un dernier choix a dû être fait : quelle version utiliser ? En effet, à l&#8217;heure où ce problème s&#8217;est posé, deux versions étaient disponibles : la 2, stable et utilisée en entreprise, et la 3 pas encore complètement publiée et jamais utilisée encore en entreprise. Malgré les risques que comportait le choix de la version 3, c&#8217;est bien cette dernière que Liferay a choisi d&#8217;utiliser, faisant le pari de l&#8217;innovation et se disant que si nécessaire, ils développeraient leurs propres plugins. Mais cette nouvelle version ne présentant pas assez de fonctionnalités pour les développeurs, ces derniers ont décidé de construire leur propre framework au dessus de YUI : <a href="http://alloy.liferay.com/">AlloyUI</a>.</p>
<p>Ainsi est né AlloyUI, ne laissant aujourd&#8217;hui plus aucune place à JQuery dans Liferay. Les équipes de Liferay ont travaillé main dans la main avec les équipes de Yahoo pour intégrer ce nouveau framework basé sur YUI 3 à Liferay, faisant d&#8217;eux la première entreprise à utiliser la version 3 d&#8217;YUI.</p>
<p>&nbsp;</p>
<p><span style="color: #666699"><strong>Prendre en main AlloyUI</strong></span></p>
<p>Nate Cavanaugh recommande aux débutants d&#8217;aller voir la librairie YUI (<a title="http://yuilibrary.com/yui/docs/examples/" href="http://yuilibrary.com/yui/docs/examples/" target="_blank">http://yuilibrary.com/yui/docs/examples/</a>). En changeant les Y par de A dans les exemples, il y a tout ce qu&#8217;il faut à cette adresse pour débuter avec AlloyUI. Cependant AlloyUI a aussi ses propres spécificités, documentées bien sûr (<a title="http://alloy.liferay.com/deploy/api/index.html" href="http://alloy.liferay.com/deploy/api/index.html" target="_blank">http://alloy.liferay.com/deploy/api/index.html</a>).</p>
<p>On retrouve notamment dans ces spécificités les fonctionnalités que Liferay aimait dans JQuery et qu&#8217;ils n&#8217;ont pas retrouvées dans YUI. Le module AutoComplete en fait partie par exemple, bien qu&#8217;il ait été ajouté à YUI postérieurement.</p>
<p>L&#8217;avantage principal avec AlloyUI et YUI, est l&#8217;utilisation d&#8217;un objet central appelé AUI avec AlloyUI et YUI avec YUI. Cette objet retourne une nouvelle instance d&#8217;YUI à chaque fois qu&#8217;il est appelé permettant notamment l&#8217;utilisation du module AutoComplete d&#8217;AlloyUI et de celui de YUI dans une sandbox sans créer de conflit particulier. Cet exemple n&#8217;aurait pas été aussi facile avec JQuery car il utilise le même objet, il aurait alors été conflictuel d&#8217;utiliser deux modules d&#8217;AutoComplete différents dans une même sandbox. Ce mécanisme de retourner une nouvelle instance est d&#8217;autant plus pratique que les portails sont des environnements dans lesquels beaucoup d&#8217;applications peuvent tourner, il est important de minimiser les conflits entre ces dernières.</p>
<p>Une difficulté lorsque l&#8217;on commence avec AlloyUI (et que l&#8217;on ne connait pas bien les modules disponibles) est de choisir le module adapté à son application. Pour pouvoir faciliter ce choix et répondre un maximum aux besoins simples des applications, Liferay a un créé module &#8220;AUI&#8221; qui regroupe la plupart des fonctionnalités (node, event, creation de composant). Faire appel à ce module vous offrira donc tout ce dont vous avez besoin. Si vous souhaitez répondre à un besoin bien particulier, il vous faudra alors vous lancer dans la recherche du module adapté.</p>
<p>Liferay 6.1 propose aussi l&#8217;utilisation de taglib pour n&#8217;importe quel widget. Mais il est parfois pénible d&#8217;utiliser les taglibs car cela impose la création d&#8217;un fichier XML, d&#8217;une JSP et d&#8217;une classe Java à faire fonctionner ensemble. C&#8217;est pourquoi Liferay a voulu proposer un &#8220;TaglibBuilder&#8221;. Ce dernier prend un fichier XML, il faut lui spécifier l&#8217;attribut et le namespace voulu et le TaglibBuilder s&#8217;occupera de la génération de la JSP et de la classe Java. Si toutefois vous devez rajouter un attribut plus tard, il vous suffira de l&#8217;ajouter au fichier XML, de relancer le TaglibBuilder et ce dernier fera les mises à jour dans les JSP et les classes. Cet outil construit l&#8217;implémentation de base d&#8217;une taglib en se basant sur la documentation du système YUI. Ainsi, plus les composants seront documentés (Javadoc), plus il sera facile d&#8217;en générer les taglibs.</p>
<p>&nbsp;</p>
<p><span style="color: #666699"><strong>Les améliorations à venir</strong></span></p>
<p>L&#8217;équipe en charge de l&#8217;interface utilisateur prévoit d&#8217;améliorer la communication en général, c&#8217;est-à-dire aussi la documentation. Nate Cavanaugh rappelle que le projet est Open Source donc que personne ne doit hésiter à partager son expérience, ses difficultés, ajouter de la documentation, poser des questions&#8230; Une <a title="https://github.com/liferay/alloy-ui" href="https://github.com/liferay/alloy-ui" target="_blank">page github</a> du projet est également disponible.</p>
<p>L&#8217;équipe a aussi le projet de mettre à disposition des exemples voués à montrer la différence entre JQuery, YUI et AlloyUI en proposant des fonctionnalités implémentées avec ces trois outils. Ainsi, l&#8217;utilisateur pourra comparer ces trois technologies et peut-être être aidé dans sa migration de l&#8217;un à l&#8217;autre.</p>
<p>&nbsp;</p>
<p><span style="color: #666699"><strong>Conclusion</strong></span></p>
<p>Cette interview de Nate Cavanaugh permet de mieux comprendre les choix des technologies faits pour l&#8217;interface utilisateur. AlloyUI a été créé pour répondre au besoin de faciliter le travail des développeurs mais aussi de sécuriser les clients de Liferay. Il semble être l&#8217;outil le plus adapté pour proposer beaucoup de fonctionnalités au niveau de l&#8217;interface et faciliter la gestion d&#8217;applications multiples dans une même page. Des efforts sont faits pour proposer plus de documentation, cependant le projet étant Open Source, tout le monde est invité à participer s&#8217;il le souhaite. Pour écouter l&#8217;interview (en Anglais), suivez ce lien : <a href="http://feeds.feedburner.com/RadioLiferay">http://feeds.feedburner.com/RadioLiferay</a>. Vous pourrez vous inscrire ou bien écouter l&#8217;article directement en cliquant sur <em>Play now</em> sous l&#8217;article concerné :<em> RL003 Nate Cavanaugh &#8211; Radio Liferay Episode 3.</em></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><!--[if IE]><iframe frameborder="0" allowTransparency="true" class="addtoany_special_service twitter_tweet" src="http://platform.twitter.com/widgets/tweet_button.html?url=http%3A%2F%2Fblog.excilys.com%2F2011%2F11%2F10%2Fradio-liferay-episode-3-nate-cavanaugh-presente-alloyui%2F&amp;counturl=http%3A%2F%2Fblog.excilys.com%2F2011%2F11%2F10%2Fradio-liferay-episode-3-nate-cavanaugh-presente-alloyui%2F&amp;count=horizontal&amp;text=Radio%20Liferay%20%26%238211%3B%20Episode%203%20%3A%20Nate%20Cavanaugh%20pr%C3%A9sente%20AlloyUI" scrolling="no" style="border:none;overflow:hidden;width:130px;height:20px"></iframe><![endif]--><!--[if !IE]><!--><iframe class="addtoany_special_service twitter_tweet" src="http://platform.twitter.com/widgets/tweet_button.html?url=http%3A%2F%2Fblog.excilys.com%2F2011%2F11%2F10%2Fradio-liferay-episode-3-nate-cavanaugh-presente-alloyui%2F&amp;counturl=http%3A%2F%2Fblog.excilys.com%2F2011%2F11%2F10%2Fradio-liferay-episode-3-nate-cavanaugh-presente-alloyui%2F&amp;count=horizontal&amp;text=Radio%20Liferay%20%26%238211%3B%20Episode%203%20%3A%20Nate%20Cavanaugh%20pr%C3%A9sente%20AlloyUI" scrolling="no" style="border:none;overflow:hidden;width:130px;height:20px"></iframe><!--<![endif]--><!--[if IE]><iframe frameborder="0" allowTransparency="true" class="addtoany_special_service google_plusone" src="https://plusone.google.com/u/0/_/%2B1/fastbutton?url=http%3A%2F%2Fblog.excilys.com%2F2011%2F11%2F10%2Fradio-liferay-episode-3-nate-cavanaugh-presente-alloyui%2F&amp;size=medium&amp;count=true" scrolling="no" style="border:none;overflow:hidden;width:90px;height:20px"></iframe><![endif]--><!--[if !IE]><!--><iframe class="addtoany_special_service google_plusone" src="https://plusone.google.com/u/0/_/%2B1/fastbutton?url=http%3A%2F%2Fblog.excilys.com%2F2011%2F11%2F10%2Fradio-liferay-episode-3-nate-cavanaugh-presente-alloyui%2F&amp;size=medium&amp;count=true" scrolling="no" style="border:none;overflow:hidden;width:90px;height:20px"></iframe><!--<![endif]--><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fblog.excilys.com%2F2011%2F11%2F10%2Fradio-liferay-episode-3-nate-cavanaugh-presente-alloyui%2F&amp;title=Radio%20Liferay%20%26%238211%3B%20Episode%203%20%3A%20Nate%20Cavanaugh%20pr%C3%A9sente%20AlloyUI" id="wpa2a_10"><img src="http://blog.excilys.com/wp-content/plugins/add-to-any/share_save_120_16.png" width="120" height="16" alt="Share"/></a></p><img src="http://feeds.feedburner.com/~r/blogexcilyscom/~4/t4S3lLGCx-o" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.excilys.com/2011/11/10/radio-liferay-episode-3-nate-cavanaugh-presente-alloyui/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://blog.excilys.com/2011/11/10/radio-liferay-episode-3-nate-cavanaugh-presente-alloyui/</feedburner:origLink></item>
		<item>
		<title>Droidcon London 2011</title>
		<link>http://feedproxy.google.com/~r/blogexcilyscom/~3/xuq9QqK67YU/</link>
		<comments>http://blog.excilys.com/2011/11/02/droidcon-london-2011/#comments</comments>
		<pubDate>Wed, 02 Nov 2011 15:30:44 +0000</pubDate>
		<dc:creator>Bastien JANSEN</dc:creator>
				<category><![CDATA[J'y étais !]]></category>
		<category><![CDATA[android]]></category>
		<category><![CDATA[conférence]]></category>
		<category><![CDATA[google]]></category>

		<guid isPermaLink="false">http://blog.excilys.com/?p=3939</guid>
		<description><![CDATA[Votre serviteur s&#8217;est rendu au pays où les escargots sont les plus heureux afin de participer à la Droidcon London 2011. Au programme de cet article, la présentation de cet évènement européen autour d&#8217;Android, et plus tard d&#8217;autres articles vous proposeront un résumé des nombreuses conférences et ateliers de barcamp de ces deux journées. Qu&#8217;est-ce [...]]]></description>
			<content:encoded><![CDATA[<p>Votre serviteur s&#8217;est rendu au pays où les escargots sont les plus heureux afin de participer à la Droidcon London 2011. Au programme de cet article, la présentation de cet évènement européen autour d&#8217;Android, et plus tard d&#8217;autres articles vous proposeront un résumé des nombreuses conférences et ateliers de barcamp de ces deux journées.</p>
<p><span id="more-3939"></span></p>
<h3>Qu&#8217;est-ce que la Droidcon ?</h3>
<div id="attachment_3944" class="wp-caption alignleft" style="width: 310px"><a href="http://blog.excilys.com/wp-content/uploads/2011/10/business_center.jpg"><img class="size-medium wp-image-3944" src="http://blog.excilys.com/wp-content/uploads/2011/10/business_center-300x225.jpg" alt="Photo du Business Design Center de nuit" width="300" height="225" /></a><p class="wp-caption-text">Business Design Center de nuit</p></div>
<p>La <strong><a title="Droidcon London" href="http://uk.droidcon.com" target="_blank">Droidcon</a></strong>, c&#8217;est une conférence autour de la plateforme mobile de <strong>Google</strong>, elle a une renommée européenne et est organisée dans 4 grandes villes chaque année : Amsterdam, Berlin, Bucarest et Londres. Les 6 et 7 octobre 2011, ce sont près de 600 personnes qui se sont réunies lors de la Droidcon au Business Design Center, à Islington, au coeur de Londres.</p>
<p>Le premier jour s&#8217;est organisé à la façon d&#8217;un <strong>barcamp</strong>. Lors de la keynote d&#8217;ouverture, toutes les personnes qui souhaitaient aborder des sujets particuliers ont proposé leurs idées. C&#8217;est ainsi qu&#8217;une trentaine d&#8217;ateliers ont été créés autour de sujets tant pour les développeurs &#8211;  comme la performance et la sécurité &#8211; que pour les non développeurs avec des sujets autour de la monétisation des applications Android par exemple.</p>
<p>Les présentations de la seconde journée étaient quant à elles déjà prévues, on a aussi retrouvé divers sujets autour du développement, du business, de l&#8217;entreprise etc.</p>
<p>Les organisateurs de cet événement étaient <strong><a title="Skills matter" href="http://skillsmatter.com/" target="_blank">Skills Matters</a></strong>, société londonienne spécialisée dans la formation informatique, et <strong>Wireless Industry Partner connector (<a title="WIP Connector" href="http://www.wipconnector.com/" target="_blank">WIP</a>)</strong>, société canadienne spécialisée dans la mise en relation d&#8217;entreprises dans le domaine mobile.</p>
<h3>Les exposants</h3>
<p>En parallèle de ces ateliers et conférences, divers exposants sont venus présenter leurs produits ou services. Voici une liste non exhaustive des exposants présents lors de cette conférence et les raisons de leur présence.</p>
<h4>Les constructeurs</h4>
<div id="attachment_3942" class="wp-caption alignright" style="width: 310px"><a href="http://blog.excilys.com/wp-content/uploads/2011/10/htcdev_booth.jpg"><img class="size-medium wp-image-3942" src="http://blog.excilys.com/wp-content/uploads/2011/10/htcdev_booth-300x225.jpg" alt="Photo du stand HTC Dev" width="300" height="225" /></a><p class="wp-caption-text">Stand HTC Dev</p></div>
<p>La société taïwanaise <strong>HTC</strong> est venue pour présenter plusieurs nouveautés :</p>
<ul>
<li>Un nouveau smartphone, le Sensation XL équipé de la technologie beats by dre qui offre une qualité sonore supérieure ;</li>
<li>Une nouvelle tablette sous honeycomb : la Jetstream avec son stylo. HTC en a profité pour nous présenter son API nommée <strong>Pen</strong> permettant d&#8217;utiliser ce stylo sur la tablette afin de transformer la tablette en véritable papier électronique.</li>
</ul>
<p>La société japonaise <strong>Sony Ericsson</strong> était également présente pour nous présenter son dernier smartphone le Xperia Play, qui est un mélange de console de jeu et de smartphone.</p>
<p>Enfin, un dernier constructeur était présent, et, bien que pouvant surprendre, il s&#8217;agissait de <strong>RIM</strong>. En effet, la société canadienne est venu courtiser les développeurs Android car leur tablette Playbook embarquera une nouvelle technologie nommée Android player. Ce player permettra aux applications Android de fonctionner sur la tablette Blackberry.</p>
<h4>Les solutions à destination des professionnels</h4>
<p>L&#8217;entreprise <strong>Cisco</strong> était présente afin de montrer sa tablette <a title="Cius sur le site de Cisco" href="http://www.cisco.com/en/US/products/ps11156/index.html" target="_blank">Cius</a> à destination des professionnels. Celle-ci dispose d&#8217;un OS basé sur Android et est vendue avec les services de communication de Cisco pré installés (Webex par exemple). A destination des professionels, elle dispose d&#8217;une connectivité plus importante que les tablettes grand public, on notera particulièrement le support de la 4G et la connectivité filaire.</p>
<p>Autre technologie représentée, Mobile Infrastructure by <strong>Sybase</strong> qui permet de réaliser de la haute disponibilité pour les données d&#8217;applications mobiles au sein d&#8217;une entreprise.</p>
<h4>Autres stands</h4>
<div id="attachment_3956" class="wp-caption alignleft" style="width: 310px"><a href="http://blog.excilys.com/wp-content/uploads/2011/10/other_booths.jpg"><img class="size-medium wp-image-3956" src="http://blog.excilys.com/wp-content/uploads/2011/10/other_booths-300x199.jpg" alt="Photo d'autres stands" width="300" height="199" /></a><p class="wp-caption-text">Photo d&#039;autres stands</p></div>
<p>Un des grands thèmes de la Droidcon était la monétisation des applications Android : comment gagner de l&#8217;argent grâce à son application ? Plusieurs plateformes publicitaires sont donc venues faire leur promotion : <strong>Inneractive</strong>, <strong>VServ</strong>, &#8230;</p>
<p>L&#8217;éditeur <strong>O&#8217;Reilly</strong> était présent le deuxième jour et proposait aux participants de la Droidcon des rabais sur ses livres. Les organisateurs possédaient également leurs stands afin de promouvoir leurs activités, Skills Matters propose d&#8217;ailleurs gratuitement un magazine trimestriel sur les <a title="Open Source Journal" href="http://skillsmatter.com/go/open-source-journal" target="_blank">technologies open source</a>. <strong>Stackoverflow.com</strong>, site web très connu chez les développeurs, est venu présenter son site <a title="Careers 2.0" href="http://careers.stackoverflow.com/" target="_blank">Careers 2.0</a>, plateforme de recrutement pour les métiers de l&#8217;informatique.</p>
<p>Enfin, deux solutions technologiques étaient représentées, il s&#8217;agit de <strong>Testdroid</strong> (dont je parlerai dans un prochain article) et de <strong>Mopapp</strong>. La première est une solution de test pour les applications Android, la seconde, quant à elle, est une solution de suivi des ventes d&#8217;applications mobiles.</p>
<p>&nbsp;</p>
<p>Voila pour la présentation de la Droidcon, promis, les prochains articles seront plus croustillants, et on y trouvera peut-être même des lignes de code <img src='http://blog.excilys.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p><!--[if IE]><iframe frameborder="0" allowTransparency="true" class="addtoany_special_service twitter_tweet" src="http://platform.twitter.com/widgets/tweet_button.html?url=http%3A%2F%2Fblog.excilys.com%2F2011%2F11%2F02%2Fdroidcon-london-2011%2F&amp;counturl=http%3A%2F%2Fblog.excilys.com%2F2011%2F11%2F02%2Fdroidcon-london-2011%2F&amp;count=horizontal&amp;text=Droidcon%20London%202011" scrolling="no" style="border:none;overflow:hidden;width:130px;height:20px"></iframe><![endif]--><!--[if !IE]><!--><iframe class="addtoany_special_service twitter_tweet" src="http://platform.twitter.com/widgets/tweet_button.html?url=http%3A%2F%2Fblog.excilys.com%2F2011%2F11%2F02%2Fdroidcon-london-2011%2F&amp;counturl=http%3A%2F%2Fblog.excilys.com%2F2011%2F11%2F02%2Fdroidcon-london-2011%2F&amp;count=horizontal&amp;text=Droidcon%20London%202011" scrolling="no" style="border:none;overflow:hidden;width:130px;height:20px"></iframe><!--<![endif]--><!--[if IE]><iframe frameborder="0" allowTransparency="true" class="addtoany_special_service google_plusone" src="https://plusone.google.com/u/0/_/%2B1/fastbutton?url=http%3A%2F%2Fblog.excilys.com%2F2011%2F11%2F02%2Fdroidcon-london-2011%2F&amp;size=medium&amp;count=true" scrolling="no" style="border:none;overflow:hidden;width:90px;height:20px"></iframe><![endif]--><!--[if !IE]><!--><iframe class="addtoany_special_service google_plusone" src="https://plusone.google.com/u/0/_/%2B1/fastbutton?url=http%3A%2F%2Fblog.excilys.com%2F2011%2F11%2F02%2Fdroidcon-london-2011%2F&amp;size=medium&amp;count=true" scrolling="no" style="border:none;overflow:hidden;width:90px;height:20px"></iframe><!--<![endif]--><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fblog.excilys.com%2F2011%2F11%2F02%2Fdroidcon-london-2011%2F&amp;title=Droidcon%20London%202011" id="wpa2a_12"><img src="http://blog.excilys.com/wp-content/plugins/add-to-any/share_save_120_16.png" width="120" height="16" alt="Share"/></a></p><img src="http://feeds.feedburner.com/~r/blogexcilyscom/~4/xuq9QqK67YU" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.excilys.com/2011/11/02/droidcon-london-2011/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://blog.excilys.com/2011/11/02/droidcon-london-2011/</feedburner:origLink></item>
		<item>
		<title>SAML 2 et Liferay – partie 2</title>
		<link>http://feedproxy.google.com/~r/blogexcilyscom/~3/Thb2DL2Hae0/</link>
		<comments>http://blog.excilys.com/2011/10/04/saml-2-et-liferay-partie-2/#comments</comments>
		<pubDate>Tue, 04 Oct 2011 11:30:13 +0000</pubDate>
		<dc:creator>Bastien JANSEN</dc:creator>
				<category><![CDATA[Non classé]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[Liferay]]></category>
		<category><![CDATA[Liferay Portal]]></category>
		<category><![CDATA[Portal]]></category>
		<category><![CDATA[SAML]]></category>

		<guid isPermaLink="false">http://blog.excilys.com/?p=3612</guid>
		<description><![CDATA[Dans le premier épisode article, nous avons vu comment intercepter l’accès à une ressource protégée dans Liferay (ou plus précisément comment lui laisser tout le boulot grâce aux mécanisme d&#8217;autologin), aujourd’hui nous allons réagir à cette agression évènement. Une bouteille à la mer Si nous reprenons le descriptif de l’échange (oui, encore, et ça ne [...]]]></description>
			<content:encoded><![CDATA[<p>Dans le premier <del>épisode</del> <a title="SAML 2 et Liferay – partie 1" href="http://blog.excilys.com/2011/09/26/saml-2-et-liferay-partie-1/">article</a>, nous avons vu comment intercepter l’accès à une ressource protégée dans Liferay (ou plus précisément comment lui laisser tout le boulot grâce aux mécanisme d&#8217;autologin), aujourd’hui nous allons réagir à cette <del>agression</del> évènement.</p>
<h3>Une bouteille à la mer</h3>
<p>Si nous reprenons le descriptif de l’échange (oui, encore, et ça ne fait que commencer…) :</p>
<p><a href="http://blog.excilys.com/wp-content/uploads/2011/09/diagrammeSAML.jpg"><img class="alignnone size-full wp-image-3572" src="http://blog.excilys.com/wp-content/uploads/2011/09/diagrammeSAML.jpg" alt="Diagramme de séquence du SSO en SAML" width="570" height="435" /></a></p>
<p><span id="more-3612"></span><br />
Nous en sommes au 2), maintenant nous devons envoyer une demande d’authentification au fournisseur d’identité, avant de vouloir aller trop vite en s’intéressant à la demande d’authentification, j’attire votre attention sur le fait que nous ne savons pas envoyer de message !</p>
<p>Comme je l’ai indiqué, plus tôt, le standard SAML utilise des « bindings » pour décrire les différents modes de transmission des messages, il en existe six, cependant le « web browser SSO profile » auquel nous nous intéressons peut être basé sur le HTTP Redirect, le HTTP Post ou le HTTP Artifact.</p>
<p>Le HTTP Redirect Binding, comme son nom l’indique, consiste à envoyer au navigateur le code HTTP Redirect avec une URL dont les paramètres contiendront le message encodé. En pratique, les limitations des navigateurs sur les longueurs des URLs peuvent poser des problèmes pour des messages longs, ce binding sera donc réservé à des messages courts.</p>
<p>Le HTTP Post Binding, consiste à répondre à la requête de l’utilisateur par une page contenant un formulaire ayant pour cible le destinataire, pour plus de transparence, la page contient généralement un script pour valider automatiquement le formulaire.</p>
<p>Le HTTP Artifact Binding se base sur l’un des deux précédents pour transmettre un « artifact », cet identifiant va ensuite être utilisé par le destinataire dans le cadre du protocole de résolution d’artifact pour récupérer le message initial via un appel direct, pouvant par exemple utiliser le binding SOAP. Ce qui a l’avantage d’éviter de faire transiter le message par le navigateur, et l’inconvénient de supposer qu’il existe un chemin de communication direct entre les deux correspondants.</p>
<p>Il est aisé de constater que le plus long à mettre en œuvre est le HTTP Artifact, puisqu’il a parmi ses pré-requis l’existence de l’un des deux autres, ce qui n’est pas très encourageant. Notre requête étant courte, nous allons privilégier le binding Redirect.</p>
<p>En regardant plus en détail, le fonctionnement de ce binding, nous constatons que, outre la requête (ou la réponse), il existe un paramètre RelayState que le fournisseur  d’identité doit nous renvoyer tel que nous l’avons renseigné, cela va nous permettre de nous « souvenir » de la page à laquelle l’utilisateur voulait accéder. Pour envoyer un message par ce mécanisme, nous devons le compresser en utilisant DEFLATE (RFC1951), puis l’encoder au format base 64 et pour finir placer le résultat dans un paramètre nommé SAMLRequest ou SAMLResponse. Malheureusement pour nous Liferay ne fournit pas d’API pour gérer la compression DEFLATE, donc on va devoir la faire nous même, en fait, on va simplement se doter d’une classe utilitaire pour simplifier les appels à Deflater et Inflater de java.util.zip :</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 />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 /></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> com.<span style="color: #006633;">liferay</span>.<span style="color: #006633;">portal</span>.<span style="color: #006633;">kernel</span>.<span style="color: #006633;">util</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #000000; font-weight: bold;">import</span> java.<span style="color: #006633;">io</span>.<span style="color: #003399;">UnsupportedEncodingException</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #000000; font-weight: bold;">import</span> java.<span style="color: #006633;">util</span>.<span style="color: #003399;">ArrayList</span><span style="color: #339933;">;</span><br />
<span style="color: #000000; font-weight: bold;">import</span> java.<span style="color: #006633;">util</span>.<span style="color: #003399;">List</span><span style="color: #339933;">;</span><br />
<span style="color: #000000; font-weight: bold;">import</span> java.<span style="color: #006633;">util</span>.<span style="color: #006633;">zip</span>.<span style="color: #003399;">DataFormatException</span><span style="color: #339933;">;</span><br />
<span style="color: #000000; font-weight: bold;">import</span> java.<span style="color: #006633;">util</span>.<span style="color: #006633;">zip</span>.<span style="color: #003399;">Deflater</span><span style="color: #339933;">;</span><br />
<span style="color: #000000; font-weight: bold;">import</span> java.<span style="color: #006633;">util</span>.<span style="color: #006633;">zip</span>.<span style="color: #003399;">Inflater</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #008000; font-style: italic; font-weight: bold;">/**<br />
 * @author Denis Vaumoron<br />
 */</span><br />
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> Deflate <span style="color: #009900;">&#123;</span><br />
<br />
        <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #000066; font-weight: bold;">byte</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> encode<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> string<span style="color: #009900;">&#41;</span><br />
                <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">UnsupportedEncodingException</span> <span style="color: #009900;">&#123;</span><br />
<br />
                <span style="color: #003399;">Deflater</span> lDeflater <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">Deflater</span><span style="color: #009900;">&#40;</span><span style="color: #003399;">Deflater</span>.<span style="color: #006633;">DEFAULT_COMPRESSION</span>, <span style="color: #000066; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
                lDeflater.<span style="color: #006633;">setInput</span><span style="color: #009900;">&#40;</span>string.<span style="color: #006633;">getBytes</span><span style="color: #009900;">&#40;</span>StringPool.<span style="color: #006633;">UTF8</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
                lDeflater.<span style="color: #006633;">finish</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
                <span style="color: #000066; font-weight: bold;">int</span> deflateLength<span style="color: #339933;">;</span><br />
                <span style="color: #000066; font-weight: bold;">byte</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> deflateBuffer <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #000066; font-weight: bold;">byte</span><span style="color: #009900;">&#91;</span>_BUFFER_SIZE<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
                <span style="color: #003399;">List</span> bufferList <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">ArrayList</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
                <span style="color: #000000; font-weight: bold;">while</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span>deflateLength <span style="color: #339933;">=</span><br />
                        lDeflater.<span style="color: #006633;">deflate</span><span style="color: #009900;">&#40;</span>deflateBuffer<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">==</span> _BUFFER_SIZE<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
<br />
                        bufferList.<span style="color: #006633;">add</span><span style="color: #009900;">&#40;</span>deflateBuffer<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
                        deflateBuffer <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #000066; font-weight: bold;">byte</span><span style="color: #009900;">&#91;</span>_BUFFER_SIZE<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
                <span style="color: #009900;">&#125;</span><br />
<br />
                <span style="color: #000066; font-weight: bold;">byte</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> deflate <span style="color: #339933;">=</span><br />
                        <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #000066; font-weight: bold;">byte</span><span style="color: #009900;">&#91;</span>bufferList.<span style="color: #006633;">size</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">*</span> _BUFFER_SIZE <span style="color: #339933;">+</span> deflateLength<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
<br />
                <span style="color: #000000; font-weight: bold;">for</span><span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">byte</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> buffer <span style="color: #339933;">:</span> bufferList<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
                        <span style="color: #003399;">System</span>.<span style="color: #006633;">arraycopy</span><span style="color: #009900;">&#40;</span>buffer, <span style="color: #cc66cc;">0</span>, deflate, <span style="color: #cc66cc;">0</span>, _BUFFER_SIZE<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
                <span style="color: #009900;">&#125;</span><br />
<br />
                <span style="color: #003399;">System</span>.<span style="color: #006633;">arraycopy</span><span style="color: #009900;">&#40;</span>deflateBuffer, <span style="color: #cc66cc;">0</span>, deflate, <span style="color: #cc66cc;">0</span>, deflateLength<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
                <span style="color: #000000; font-weight: bold;">return</span> deflate<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: #000000; font-weight: bold;">static</span> <span style="color: #003399;">String</span> decode<span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">byte</span> raw<span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><br />
                <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">UnsupportedEncodingException</span>, <span style="color: #003399;">DataFormatException</span> <span style="color: #009900;">&#123;</span><br />
<br />
                <span style="color: #003399;">Inflater</span> inflater <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">Inflater</span><span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
                inflater.<span style="color: #006633;">setInput</span><span style="color: #009900;">&#40;</span>raw<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
                <span style="color: #000066; font-weight: bold;">int</span> resultLength<span style="color: #339933;">;</span><br />
                <span style="color: #000066; font-weight: bold;">byte</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> valueBytes <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #000066; font-weight: bold;">byte</span><span style="color: #009900;">&#91;</span>_BUFFER_SIZE<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
                StringBundler inflateBuffer <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> StringBundler<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
                <span style="color: #000000; font-weight: bold;">while</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span>resultLength <span style="color: #339933;">=</span> inflater.<span style="color: #006633;">inflate</span><span style="color: #009900;">&#40;</span>valueBytes<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">!=</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
                        inflateBuffer.<span style="color: #006633;">append</span><span style="color: #009900;">&#40;</span><br />
                                <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">String</span><span style="color: #009900;">&#40;</span>valueBytes, <span style="color: #cc66cc;">0</span>, resultLength, StringPool.<span style="color: #006633;">UTF8</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
                <span style="color: #009900;">&#125;</span><br />
                inflater.<span style="color: #006633;">end</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;">return</span> inflateBuffer.<span style="color: #006633;">toString</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 />
<br />
        <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #000066; font-weight: bold;">int</span> _BUFFER_SIZE <span style="color: #339933;">=</span> <span style="color: #cc66cc;">1024</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div>
</pre>
<p>Pour l’encodage base 64, on peut utiliser com.liferay.portal.kernel.util.Base64, ce qui donne le bout de 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 /></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: #000066; font-weight: bold;">byte</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> samlDeflate <span style="color: #339933;">=</span> Deflate.<span style="color: #006633;">encode</span><span style="color: #009900;">&#40;</span>saml<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #003399;">String</span> samlBase64 <span style="color: #339933;">=</span> Base64.<span style="color: #006633;">encode</span><span style="color: #009900;">&#40;</span>samlDeflate<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></td></tr></tbody></table></div>
</pre>
<p>Plutôt simple non ? C’est probablement parce que je n’ai pas mentionné que pour le profile web browser SSO, il est recommandé d’utiliser https (bon ok, c’est une fausse difficulté, cela se configure au niveau du serveur d’application), et de signer les messages (dans le cas où l’identification du fournisseur de service doit être vérifiée (ce n’est pas toujours le cas ? je me demande à quoi sert cette précision, si le fournisseur d’identité répond à « n’importe qui » avec toutes les informations sur l’utilisateur…)). Pour signer le message, il faut rajouter deux paramètres, SigAlg pour indiquer l’URI  de l’algorithme de signature utilisé et Signature pour la signature (que de surprise dans cet article) qui doit être encodé en base 64. La signature s’effectue sur les paramètres classés dans l’ordre SAMLRequest (ou SAMLResponse), RelayState (le paramètre ne doit pas apparaitre si la valeur est vide), puis SigAlg. Les algorithmes de signature DSAwithSHA1 et RSAwithSHA1 doivent être supportés, pour nous faciliter la vie nous allons utiliser java.security.Signature :</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 />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 />84<br />85<br />86<br />87<br />88<br />89<br />90<br />91<br /></div></td><td><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #003399;">String</span> getHTTPRedirectBindingUrl<span style="color: #009900;">&#40;</span><br />
                        <span style="color: #003399;">String</span> serviceUrl, <span style="color: #000066; font-weight: bold;">boolean</span> isRequest,<br />
                        <span style="color: #003399;">String</span> saml, <span style="color: #003399;">String</span> relayState, <span style="color: #003399;">String</span> signAlg<span style="color: #009900;">&#41;</span><br />
                <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">SystemException</span>, <span style="color: #003399;">IOException</span>, <span style="color: #003399;">GeneralSecurityException</span> <span style="color: #009900;">&#123;</span><br />
<br />
                <span style="color: #000066; font-weight: bold;">byte</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> samlDeflate <span style="color: #339933;">=</span> Deflate.<span style="color: #006633;">encode</span><span style="color: #009900;">&#40;</span>saml<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
                <span style="color: #003399;">String</span> samlBase64 <span style="color: #339933;">=</span> Base64.<span style="color: #006633;">encode</span><span style="color: #009900;">&#40;</span>samlDeflate<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
                StringBundler url <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> StringBundler<span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">7</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
                url.<span style="color: #006633;">append</span><span style="color: #009900;">&#40;</span>serviceUrl<span style="color: #009900;">&#41;</span>.<span style="color: #006633;">append</span><span style="color: #009900;">&#40;</span>StringPool.<span style="color: #006633;">QUESTION</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
                StringBundler urlParamBuffer <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> StringBundler<span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">11</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
                <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>isRequest<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
                        urlParamBuffer.<span style="color: #006633;">append</span><span style="color: #009900;">&#40;</span>SAMLConstants.<span style="color: #006633;">SAML_REQUEST</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
                <span style="color: #009900;">&#125;</span><br />
                <span style="color: #000000; font-weight: bold;">else</span> <span style="color: #009900;">&#123;</span><br />
                        urlParamBuffer.<span style="color: #006633;">append</span><span style="color: #009900;">&#40;</span>SAMLConstants.<span style="color: #006633;">SAML_RESPONSE</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
                <span style="color: #009900;">&#125;</span><br />
                urlParamBuffer.<span style="color: #006633;">append</span><span style="color: #009900;">&#40;</span>StringPool.<span style="color: #006633;">EQUAL</span><span style="color: #009900;">&#41;</span><br />
                        .<span style="color: #006633;">append</span><span style="color: #009900;">&#40;</span>HttpUtil.<span style="color: #006633;">encodeURL</span><span style="color: #009900;">&#40;</span>samlBase64<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
                <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>Validator.<span style="color: #006633;">isNotNull</span><span style="color: #009900;">&#40;</span>relayState<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
                        urlParamBuffer.<span style="color: #006633;">append</span><span style="color: #009900;">&#40;</span>StringPool.<span style="color: #006633;">AMPERSAND</span><span style="color: #009900;">&#41;</span><br />
                                .<span style="color: #006633;">append</span><span style="color: #009900;">&#40;</span>SAMLConstants.<span style="color: #006633;">RELAY_STATE</span><span style="color: #009900;">&#41;</span><br />
                                .<span style="color: #006633;">append</span><span style="color: #009900;">&#40;</span>StringPool.<span style="color: #006633;">EQUAL</span><span style="color: #009900;">&#41;</span><br />
                                .<span style="color: #006633;">append</span><span style="color: #009900;">&#40;</span>HttpUtil.<span style="color: #006633;">encodeURL</span><span style="color: #009900;">&#40;</span>relayState<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
                <span style="color: #009900;">&#125;</span><br />
<br />
                urlParamBuffer.<span style="color: #006633;">append</span><span style="color: #009900;">&#40;</span>StringPool.<span style="color: #006633;">AMPERSAND</span><span style="color: #009900;">&#41;</span><br />
                        .<span style="color: #006633;">append</span><span style="color: #009900;">&#40;</span>SAMLConstants.<span style="color: #006633;">SIG_ALG</span><span style="color: #009900;">&#41;</span><br />
                        .<span style="color: #006633;">append</span><span style="color: #009900;">&#40;</span>StringPool.<span style="color: #006633;">EQUAL</span><span style="color: #009900;">&#41;</span><br />
                        .<span style="color: #006633;">append</span><span style="color: #009900;">&#40;</span>HttpUtil.<span style="color: #006633;">encodeURL</span><span style="color: #009900;">&#40;</span><br />
                                _getURIFromSignAlg<span style="color: #009900;">&#40;</span>signAlg<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
                <span style="color: #003399;">String</span> urlParameters <span style="color: #339933;">=</span> urlParamBuffer.<span style="color: #006633;">toString</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
                url.<span style="color: #006633;">append</span><span style="color: #009900;">&#40;</span>urlParameters<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
                url.<span style="color: #006633;">append</span><span style="color: #009900;">&#40;</span>StringPool.<span style="color: #006633;">AMPERSAND</span><span style="color: #009900;">&#41;</span><br />
                        .<span style="color: #006633;">append</span><span style="color: #009900;">&#40;</span>SAMLConstants.<span style="color: #006633;">SIGNATURE</span><span style="color: #009900;">&#41;</span><br />
                        .<span style="color: #006633;">append</span><span style="color: #009900;">&#40;</span>StringPool.<span style="color: #006633;">EQUAL</span><span style="color: #009900;">&#41;</span><br />
                        .<span style="color: #006633;">append</span><span style="color: #009900;">&#40;</span>_signUrlParameter<span style="color: #009900;">&#40;</span>urlParameters, signAlg<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
                <span style="color: #000000; font-weight: bold;">return</span> url.<span style="color: #006633;">toString</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 />
<br />
        <span style="color: #008000; font-style: italic; font-weight: bold;">/**<br />
         * Cette  méthode doit être utilisée avant l'envoi de la réponse,<br />
         * afin d'initialiser les en-têtes corrects.<br />
         *<br />
         * @param response<br />
         */</span><br />
        <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #000066; font-weight: bold;">void</span> initHTTPHeader<span style="color: #009900;">&#40;</span>HttpServletResponse response<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
                response.<span style="color: #006633;">setHeader</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Cache-Control&quot;</span>, <span style="color: #0000ff;">&quot;no-cache, no-store&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
                response.<span style="color: #006633;">setHeader</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Pragma&quot;</span>, <span style="color: #0000ff;">&quot;no-cache&quot;</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;">private</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #003399;">String</span> _signUrlParameter<span style="color: #009900;">&#40;</span><br />
                        <span style="color: #003399;">String</span> urlParameter, <span style="color: #003399;">String</span> signAlg<span style="color: #009900;">&#41;</span><br />
                <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">SystemException</span>, <span style="color: #003399;">IOException</span>, <span style="color: #003399;">GeneralSecurityException</span> <span style="color: #009900;">&#123;</span><br />
<br />
                <span style="color: #666666; font-style: italic;">// les noms d'algorithme ne suivent pas la même nomenclature</span><br />
                <span style="color: #666666; font-style: italic;">// dans SAML et dans java.security, donc on doit convertir.</span><br />
<br />
                <span style="color: #003399;">Signature</span> signature <span style="color: #339933;">=</span> <span style="color: #003399;">Signature</span>.<span style="color: #006633;">getInstance</span><span style="color: #009900;">&#40;</span><br />
                        _getAlgorithmFromSignAlg<span style="color: #009900;">&#40;</span>signAlg<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
                signature.<span style="color: #006633;">initSign</span><span style="color: #009900;">&#40;</span>SAMLMetadataManager.<span style="color: #006633;">getSPPrivateKey</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 />
<br />
                signature.<span style="color: #006633;">update</span><span style="color: #009900;">&#40;</span>urlParameter.<span style="color: #006633;">getBytes</span><span style="color: #009900;">&#40;</span>StringPool.<span style="color: #006633;">UTF8</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
                <span style="color: #000000; font-weight: bold;">return</span> HttpUtil.<span style="color: #006633;">encodeURL</span><span style="color: #009900;">&#40;</span>Base64.<span style="color: #006633;">encode</span><span style="color: #009900;">&#40;</span>signature.<span style="color: #006633;">sign</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</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;">private</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #003399;">String</span> _getURIFromSignAlg<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> signAlg<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
                <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>_DSA_WITH_SHA1.<span style="color: #006633;">equals</span><span style="color: #009900;">&#40;</span>signAlg<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
                        <span style="color: #000000; font-weight: bold;">return</span> SignatureMethod.<span style="color: #006633;">DSA_SHA1</span><span style="color: #339933;">;</span><br />
                <span style="color: #009900;">&#125;</span><br />
                <span style="color: #000000; font-weight: bold;">return</span> SignatureMethod.<span style="color: #006633;">RSA_SHA1</span><span style="color: #339933;">;</span><br />
        <span style="color: #009900;">&#125;</span><br />
<br />
        <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #003399;">String</span> _getAlgorithmFromSignAlg<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> signAlg<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
                <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>_DSA_WITH_SHA1.<span style="color: #006633;">equals</span><span style="color: #009900;">&#40;</span>signAlg<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
                        <span style="color: #000000; font-weight: bold;">return</span> _SHA1_WITH_DSA<span style="color: #339933;">;</span><br />
                <span style="color: #009900;">&#125;</span><br />
                <span style="color: #000000; font-weight: bold;">return</span> _SHA1_WITH_RSA<span style="color: #339933;">;</span><br />
        <span style="color: #009900;">&#125;</span><br />
<br />
        <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">String</span> _DSA_WITH_SHA1 <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;DSAwithSHA1&quot;</span><span style="color: #339933;">;</span><br />
<br />
        <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">String</span> _SHA1_WITH_DSA <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;SHA1withDSA&quot;</span><span style="color: #339933;">;</span><br />
<br />
        <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">String</span> _SHA1_WITH_RSA <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;SHA1withRSA&quot;</span><span style="color: #339933;">;</span></div></td></tr></tbody></table></div>
</pre>
<p>Remarque : la méthode getSPPrivateKey de la classe SAMLMetadataManager (comme son nom ne l’indique pas) me permet de récupérer la PrivateKey associée au KeyStore qui contient ma clé. En attendant <del>le sublime final de la troisième saison</del> la troisième partie de cette série d’articles (qui concernera la gestion des métadonnées), vous pouvez lire la clé dans votre keystore de la manière suivante :</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 /></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: #003399;">KeyStore</span> keystore <span style="color: #339933;">=</span> <span style="color: #003399;">KeyStore</span>.<span style="color: #006633;">getInstance</span><span style="color: #009900;">&#40;</span>“jks”<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
keystore.<span style="color: #006633;">load</span><span style="color: #009900;">&#40;</span><br />
        <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">FileInputStream</span><span style="color: #009900;">&#40;</span>“chemin<span style="color: #339933;">/</span>vers<span style="color: #339933;">/</span>monkeystore.<span style="color: #006633;">jks</span>”<span style="color: #009900;">&#41;</span>,<br />
        “MotDePasseDuKeyStore”.<span style="color: #006633;">toCharArray</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 />
<br />
<span style="color: #003399;">PrivateKey</span> spPrivateKey <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span><span style="color: #003399;">PrivateKey</span><span style="color: #009900;">&#41;</span> keystore.<span style="color: #006633;">getKey</span><span style="color: #009900;">&#40;</span><br />
        “aliasDeLaClePrivee”,<br />
        “MotDePasseDeLaClePrivee”.<span style="color: #006633;">toCharArray</span><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>Pour générer le fameux keystore et la clé correspondante, vous n’avez qu’à utiliser la commande suivante (keytool fait partie des outils fournit avec le JDK, faites un keytool &#8211;help si besoin) :</p>
<pre>keytool –genkey -keyalg RSA -alias aliasDeLaClePrivee –keypass MotDePasseDeLaClePrivee –keystore monkeystore.jks
    –storepass MotDePasseDuKeyStore</pre>
<p>&nbsp;</p>
<h3>C’est fini pour aujourd’hui</h3>
<p>Et voila, nous avons notre bouteille, autrement dit nous sommes maintenant capable d’envoyer un message, vous en savez aussi un peu plus sur les « bindings » de SAML, nous verrons dans le prochain article comment générer la demande d’authentification, après tout on jette rarement à la mer une bouteille vide.</p>
<p>A bientôt pour de nouvelles aventures sur le blog Excilys…</p>
<p>&nbsp;</p>
<p><!--[if IE]><iframe frameborder="0" allowTransparency="true" class="addtoany_special_service twitter_tweet" src="http://platform.twitter.com/widgets/tweet_button.html?url=http%3A%2F%2Fblog.excilys.com%2F2011%2F10%2F04%2Fsaml-2-et-liferay-partie-2%2F&amp;counturl=http%3A%2F%2Fblog.excilys.com%2F2011%2F10%2F04%2Fsaml-2-et-liferay-partie-2%2F&amp;count=horizontal&amp;text=SAML%202%20et%20Liferay%20%26%238211%3B%20partie%202" scrolling="no" style="border:none;overflow:hidden;width:130px;height:20px"></iframe><![endif]--><!--[if !IE]><!--><iframe class="addtoany_special_service twitter_tweet" src="http://platform.twitter.com/widgets/tweet_button.html?url=http%3A%2F%2Fblog.excilys.com%2F2011%2F10%2F04%2Fsaml-2-et-liferay-partie-2%2F&amp;counturl=http%3A%2F%2Fblog.excilys.com%2F2011%2F10%2F04%2Fsaml-2-et-liferay-partie-2%2F&amp;count=horizontal&amp;text=SAML%202%20et%20Liferay%20%26%238211%3B%20partie%202" scrolling="no" style="border:none;overflow:hidden;width:130px;height:20px"></iframe><!--<![endif]--><!--[if IE]><iframe frameborder="0" allowTransparency="true" class="addtoany_special_service google_plusone" src="https://plusone.google.com/u/0/_/%2B1/fastbutton?url=http%3A%2F%2Fblog.excilys.com%2F2011%2F10%2F04%2Fsaml-2-et-liferay-partie-2%2F&amp;size=medium&amp;count=true" scrolling="no" style="border:none;overflow:hidden;width:90px;height:20px"></iframe><![endif]--><!--[if !IE]><!--><iframe class="addtoany_special_service google_plusone" src="https://plusone.google.com/u/0/_/%2B1/fastbutton?url=http%3A%2F%2Fblog.excilys.com%2F2011%2F10%2F04%2Fsaml-2-et-liferay-partie-2%2F&amp;size=medium&amp;count=true" scrolling="no" style="border:none;overflow:hidden;width:90px;height:20px"></iframe><!--<![endif]--><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fblog.excilys.com%2F2011%2F10%2F04%2Fsaml-2-et-liferay-partie-2%2F&amp;title=SAML%202%20et%20Liferay%20%26%238211%3B%20partie%202" id="wpa2a_14"><img src="http://blog.excilys.com/wp-content/plugins/add-to-any/share_save_120_16.png" width="120" height="16" alt="Share"/></a></p><img src="http://feeds.feedburner.com/~r/blogexcilyscom/~4/Thb2DL2Hae0" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.excilys.com/2011/10/04/saml-2-et-liferay-partie-2/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://blog.excilys.com/2011/10/04/saml-2-et-liferay-partie-2/</feedburner:origLink></item>
		<item>
		<title>L’aventure Kwixo.com</title>
		<link>http://feedproxy.google.com/~r/blogexcilyscom/~3/yCFQZdvf0xs/</link>
		<comments>http://blog.excilys.com/2011/09/27/laventure-kwixo-com/#comments</comments>
		<pubDate>Tue, 27 Sep 2011 17:08:09 +0000</pubDate>
		<dc:creator>David DUPONCHEL</dc:creator>
				<category><![CDATA[Non classé]]></category>
		<category><![CDATA[kwixo.com]]></category>

		<guid isPermaLink="false">http://blog.excilys.com/?p=3490</guid>
		<description><![CDATA[Quésako Vous avez sûrement déjà vu les pubs à la télé qui mettent en scène des nudistes en train de chercher leur portefeuille. Mais pourquoi ? Tout simplement parce qu’avec Kwixo, plus besoin de portefeuille, on peut payer avec son téléphone mobile pour rembourser un ami nudiste (ou pas d&#8217;ailleurs[a]). Mais ce n’est pas tout, [...]]]></description>
			<content:encoded><![CDATA[<div style="text-align: justify;">
<h3>Quésako</h3>
<p>Vous avez sûrement déjà vu les <a href="http://www.youtube.com/watch?v=xCBzia6iMKo">pubs</a> <a href="http://www.youtube.com/watch?v=k6shf00hAvY">à</a> <a href="http://www.youtube.com/watch?v=NFeVvBWyUyM">la</a> <a href="http://www.youtube.com/watch?v=oEvRn3fx1II">télé</a> qui mettent en scène des nudistes en train de chercher leur portefeuille. Mais pourquoi ? Tout simplement parce qu’avec Kwixo, plus besoin de portefeuille, on peut payer avec son téléphone mobile pour rembourser un ami nudiste (ou pas d&#8217;ailleurs<sup><a name="cmnt_ref1" href="#cmnt1">[a]</a></sup>).</p>
<div style="margin: 0 0 20px 20px; float: right;">
<p><object width="500" height="281"><param name="movie" value="http://www.youtube.com/v/NFeVvBWyUyM?version=3"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/NFeVvBWyUyM?version=3" type="application/x-shockwave-flash" width="500" height="281" allowscriptaccess="always" allowfullscreen="true"></embed></object></p>
</div>
<div style="text-align: center;"><a href="https://www.kwixo.com/"><img class="alignnone size-full wp-image-3504" src="http://blog.excilys.com/wp-content/uploads/2011/09/logo_kwixo.png" alt="" width="190" height="55" /></a></div>
<p>Mais ce n’est pas tout, Kwixo c’est également une solution pour payer sur internet chez des e-commerçants. Elle propose entre autres le paiement après réception mais aussi le paiement à crédit. Un login, un mot de passe et dites adieux aux numéros de cartes de crédit à rentrer sur un site dont vous ne savez même pas ce qu’ils vont en faire.</p>
<p>En bref, vous l’aurez compris, Kwixo s’annonce comme un sérieux concurrent du célèbre Paypal et nous sommes très fiers d’avoir pu contribuer par notre expertise technique.</p>
<p><span id="more-3490"></span></p>
<h3 style="clear: both;">Kwixo en chiffres</h3>
<p>Une équipe de 20 personnes, dont 10 développeurs JavaEE, a sué sang et eau pendant deux années pour mettre au point ce projet qui, du point de vue technique, est parti de ZÉRO. En plus des problématiques techniques liées au démarrage, nous avons rencontré des problématiques d’intendance : pas de serveur pour le SCM<sup><a name="cmnt_ref2" href="#cmnt2">[b]</a></sup>, une connection internet filtrée qui bloquait certains repository maven, des changements de locaux inopinés mais ce n&#8217;est pas ce qui nous a arrêté.</p>
<p>Au bout de deux ans, que dire ? Que nous avons effectué plus de <strong>17 000</strong> commits avec Git, environ <strong>5 000</strong> <a href="http://blog.octo.com/gestion-de-version-distribuee-et-build-incassable/">builds incassables</a> avec Hudson/Jenkins, <strong>210 000</strong> lignes de Java (hors imports), <strong>600</strong> fichiers XML&#8230; Cela commence à donner une bonne idée de ce qu’est Kwixo. Derrière ces chiffres (magie des mathématiques), on trouve d’autres chiffres: 7 webapps, une base de données classique (sybase), une base de données NoSQL (CouchDB), <strong>40 webservices</strong> REST/JSON, 30 batches, et 30 flows spring-webflow. Ça se précise.</p>
<p>Ajoutez enfin des processus fonctionnels compliqués, par exemple celui de l’inscription sur le site. 5 écrans.</p>
<table>
<tbody>
<tr>
<td rowspan="5"><img class="alignnone size-medium wp-image-3520" src="http://blog.excilys.com/wp-content/uploads/2011/09/registration1.png" alt="" width="125" height="500" /></td>
<td height="100">
<ul>
<li>Validations classiques : Nom, Prénom, Âge</li>
</ul>
</td>
</tr>
<tr>
<td height="100">
<ul>
<li>Vérification de l&#8217;unicité de l&#8217;e-mail</li>
<li>Vérification de l&#8217;unicité du mobile</li>
<li>Vérification des transactions en attente</li>
<li>Validation par One-Time Password du mobile</li>
</ul>
</td>
</tr>
<tr>
<td height="100">
<ul>
<li>Vérification de l&#8217;unicité du moyen de paiement</li>
<li>Utilisation d&#8217;iframe pour PCI-DSS</li>
</ul>
</td>
</tr>
<tr>
<td height="100">
<ul>
<li>idem point (3)</li>
</ul>
</td>
</tr>
<tr>
<td height="100">
<ul>
<li>Création du compte</li>
<li>Affichage des données saisies</li>
<li>Envoi du mail de confirmation avec lien de validation</li>
</ul>
</td>
</tr>
</tbody>
</table>
<p>Comme vous pouvez le constater, lorsqu’on ajoute les différents contrôles,  tout se complexifie.</p>
<p>Au point d’en arriver <strong><a href="http://blog.excilys.com/wp-content/uploads/2011/09/diagram.png">ici</a></strong>. Voici une bonne idée de ce qu&#8217;est Kwixo d&#8217;un point de vue technique.</p>
<h3>Kwic-flow</h3>
<p>Pourquoi Webflow plutôt qu’un moteur de BPM “classique” ? Parce que Webflow s&#8217;intéresse essentiellement à la gestion des enchaînements Web. Il s’agit d’une version “survitaminée” de SpringMVC. C’est pourquoi Kwixo (avec ses nombreuses procédures pas-à-pas) en fait une utilisation massive.</p>
<p>Nous avons d’abord tâtonné en nous penchant sur la (maigre) documentation officielle. Mais force a été de constater que la documentation n’est pas maigre mais bien rachitique. Et les articles de blogs et autres présentations ne vont que rarement au delà de la découverte du framework.</p>
<p>C’est pourquoi nous vous présenterons un retour d’expérience sur Webflow au travers d’une série d’articles sur les différentes techniques que nous avons mises en oeuvre, parmi lesquelles :</p>
<ul>
<li>Gestion du bouton précédent du navigateur. Sur le papier, cette fonctionnalité est déjà offerte par webflow. En réalité, bien que webflow embarque toute la mécanique pour le détecter “out of the box”, charge au développeur de faire en sorte que l’utilisateur soit prévenu de manière un peu plus claire que “Une erreur est survenue”.</li>
<li>Réutilisation de code et factorisation : les subflow et l’héritage. Webflow propose des méthodes pour réutiliser des parties de cinématique d’écrans. Nous verrons comment les mettre en oeuvre au travers d’une validation par OTP d’un mobile.</li>
</ul>
<p>Et comme un bon retour d’expérience ne saurait être exempt de toute critique, nous nous prendrons à rêver aux alternatives que nous aurions pu trouver à Webflow.</p>
<h3>Les messages so quick</h3>
<div style="margin: 10px; float: left;"><img class="alignnone size-full wp-image-3557" src="http://blog.excilys.com/wp-content/uploads/2011/09/mail_new1.png" alt="Icône Mail" width="128" height="128" /></div>
<p>Kwixo envoie aussi des e-mails, des SMS et affiche des alertes et des notifications à droite à gauche. Un bombardement continu de messages très différents les uns des autres, sur plusieurs canaux (SMS, web, e-mail) et aux contenus délicatement ciselés et régulièrement revus par les services marketing et juridique.</p>
<p>Pour faire fonctionner tout ça de manière transparente, non-bloquante pour les processus métier et accessible par le <a href="http://fr.wikipedia.org/wiki/Ma%C3%AEtrise_d%27ouvrage">commun</a> <a href="http://fr.wikipedia.org/wiki/Marketing">des</a> <a href="http://fr.wikipedia.org/wiki/Juriste">mortels</a>, Kwixo s’est bien creusé la tête. Il a étudié diverses options séduisantes (“j’ai une idée! on va mettre des annotations partout”), et après refactoring intense a fini par porter son choix sur son architecture de messaging actuelle.</p>
<p>Parmi les ingrédients du cocktail final, on trouve de l’évènementiel, du JMS, du NoSqL et des processus démoniaques.</p>
<p>Recette à suivre &#8230;</p>
<div style="margin: 20px 0;">
<h3>Notes</h3>
<p><a name="cmnt1" href="#cmnt_ref1">[a]</a> Kwixo accepte aussi les gens habillés, s&#8217;ils acceptent d&#8217;enlever au moins leur chemise.<br />
<a name="cmnt2" href="#cmnt_ref2">[b]</a> Ce qui a eu pour effet très bénéfique de nous conforter dans le choix de GIT !</p>
</div>
<p>L&#8217;icône du mail est sous licence GPL et a été crée par <a href="http://www.mentalrey.it/">Alessandro Rei</a></p>
</div>
<p><!--[if IE]><iframe frameborder="0" allowTransparency="true" class="addtoany_special_service twitter_tweet" src="http://platform.twitter.com/widgets/tweet_button.html?url=http%3A%2F%2Fblog.excilys.com%2F2011%2F09%2F27%2Flaventure-kwixo-com%2F&amp;counturl=http%3A%2F%2Fblog.excilys.com%2F2011%2F09%2F27%2Flaventure-kwixo-com%2F&amp;count=horizontal&amp;text=L%26%238217%3Baventure%20Kwixo.com" scrolling="no" style="border:none;overflow:hidden;width:130px;height:20px"></iframe><![endif]--><!--[if !IE]><!--><iframe class="addtoany_special_service twitter_tweet" src="http://platform.twitter.com/widgets/tweet_button.html?url=http%3A%2F%2Fblog.excilys.com%2F2011%2F09%2F27%2Flaventure-kwixo-com%2F&amp;counturl=http%3A%2F%2Fblog.excilys.com%2F2011%2F09%2F27%2Flaventure-kwixo-com%2F&amp;count=horizontal&amp;text=L%26%238217%3Baventure%20Kwixo.com" scrolling="no" style="border:none;overflow:hidden;width:130px;height:20px"></iframe><!--<![endif]--><!--[if IE]><iframe frameborder="0" allowTransparency="true" class="addtoany_special_service google_plusone" src="https://plusone.google.com/u/0/_/%2B1/fastbutton?url=http%3A%2F%2Fblog.excilys.com%2F2011%2F09%2F27%2Flaventure-kwixo-com%2F&amp;size=medium&amp;count=true" scrolling="no" style="border:none;overflow:hidden;width:90px;height:20px"></iframe><![endif]--><!--[if !IE]><!--><iframe class="addtoany_special_service google_plusone" src="https://plusone.google.com/u/0/_/%2B1/fastbutton?url=http%3A%2F%2Fblog.excilys.com%2F2011%2F09%2F27%2Flaventure-kwixo-com%2F&amp;size=medium&amp;count=true" scrolling="no" style="border:none;overflow:hidden;width:90px;height:20px"></iframe><!--<![endif]--><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fblog.excilys.com%2F2011%2F09%2F27%2Flaventure-kwixo-com%2F&amp;title=L%26%238217%3Baventure%20Kwixo.com" id="wpa2a_16"><img src="http://blog.excilys.com/wp-content/plugins/add-to-any/share_save_120_16.png" width="120" height="16" alt="Share"/></a></p><img src="http://feeds.feedburner.com/~r/blogexcilyscom/~4/yCFQZdvf0xs" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.excilys.com/2011/09/27/laventure-kwixo-com/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://blog.excilys.com/2011/09/27/laventure-kwixo-com/</feedburner:origLink></item>
		<item>
		<title>SAML 2 et Liferay – partie 1</title>
		<link>http://feedproxy.google.com/~r/blogexcilyscom/~3/nR5ZJppUbfI/</link>
		<comments>http://blog.excilys.com/2011/09/26/saml-2-et-liferay-partie-1/#comments</comments>
		<pubDate>Mon, 26 Sep 2011 14:01:23 +0000</pubDate>
		<dc:creator>Denis VAUMORON</dc:creator>
				<category><![CDATA[Non classé]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[Liferay]]></category>
		<category><![CDATA[Liferay Portal]]></category>
		<category><![CDATA[Portal]]></category>
		<category><![CDATA[SAML]]></category>

		<guid isPermaLink="false">http://blog.excilys.com/?p=3571</guid>
		<description><![CDATA[Cette suite d’articles a pour objectif de présenter l’intégration d’un portail Liferay en tant que fournisseur de services dans une fédération d’identité basé sur SAML 2.0 (authentification et déconnexion unique (SSO et SLO)). Le travail décrit fait partie d’un développement sponsorisé qui a été reversé à la communauté (voir LPS-8427), et devrait être disponible dans [...]]]></description>
			<content:encoded><![CDATA[<p>Cette suite d’articles a pour objectif de présenter l’intégration d’un portail Liferay en tant que fournisseur de services dans une fédération d’identité basé sur SAML 2.0 (authentification et déconnexion unique (SSO et SLO)). Le travail décrit fait partie d’un développement sponsorisé qui a été reversé à la communauté (voir <a href="http://issues.liferay.com/browse/LPS-8427">LPS-8427</a>), et devrait être disponible dans la version 6.1 de Liferay, le patch proposé supporte aussi la version 1.1 de SAML, celle-ci étant moins complète que la version 2.0, nous ne nous y intéresserons pas ici.</p>
<p>Dans les premiers articles, nous allons voir comment gérer l’authentification unique, la deuxième partie aura pour sujet la déconnexion centralisée, et la série s’arrêtera avec <del>une apothéose pour la fin de la saison 3</del> une troisième partie pour traiter d’une pierre deux coups, la correspondance entre les attributs et l’utilisation des métadonnées.</p>
<p>Bien que cette série d’articles soit une application au portail Liferay, elle traite essentiellement de SAML 2.0, et fournit les bases pour l’intégration de ce standard à une application JEE.</p>
<h3>Rappel sur les protagonistes</h3>
<p><a href="http://www.liferay.com/">Liferay</a> est un portail JEE <del>top moumoute</del> (où donc ai-je pris ces mauvaises habitudes de langages ???) très abouti, il est compatible avec les spécifications portlets 1.0 et 2.0 (respectivement JSR 168 et JSR 286), et fournit nativement un grand nombre de fonctionnalités (CMS, forum, wiki, blog, etc. …). I</p>
<p><a href="http://saml.xml.org/">SAML</a> (pour Security Assertion Markup Language) est un standard développé par l&#8217;<a title="Organization for the Advancement of Structured Information Standards" href="http://www.oasis-open.org/">OASIS</a> pour la fédération d’identité, basé sur des échanges de messages XML, qui comporte des assertions (les fameux messages XML), des protocoles (autrement dit des échanges de messages, avec format des requêtes et des réponses), des « bindings » (comprendre un mode de transmission des messages) et des « profiles » (scénario s’appuyant sur les éléments précédents pour décrire un cas concret, par exemple l’authentification unique d’un navigateur (Web Browser SSO Profile)).</p>
<p><span id="more-3571"></span></p>
<h3>L’authentification unique</h3>
<p>Avant de pouvoir se déconnecter de manière centralisée, il faut déjà s’être connecté, pour cela, regardons plus en détail le « Web Browser SSO Profile ».</p>
<p>Ce scénario comporte 3 acteurs, l’utilisateur (via son navigateur), le fournisseur de services (ou SP, Service Provider, Liferay dans notre cas) et un fournisseur d’identité (ou IdP, Identity Provider, pour mes tests j’avais mis en place <a href="http://simplesamlphp.org/">SimpleSAMLphp</a> sur un server <a href="http://www.wampserver.com/">WAMP</a>) :</p>
<p><a href="http://blog.excilys.com/wp-content/uploads/2011/09/diagrammeSAML.jpg"><img class="alignnone size-full wp-image-3572" src="http://blog.excilys.com/wp-content/uploads/2011/09/diagrammeSAML.jpg" alt="Diagramme de séquence du SSO en SAML" width="570" height="435" /></a></p>
<ol>
<li>L’utilisateur tente d’accéder à une ressource protégée du fournisseur de services sans contexte de sécurité</li>
<li>Le fournisseur de service envoie une demande d’authentification au fournisseur d’identité (message &lt;AuthnRequest&gt;) à travers le navigateur (redirection ou page générant un POST automatique)</li>
<li>Le fournisseur d’identité identifie l’utilisateur (page de connexion ou utilisation d’une session pré-existante)</li>
<li>Le fournisseur d’identité envoie une réponse au fournisseur de services (message &lt;Response&gt;, toujours en passant par le navigateur)</li>
<li>Le fournisseur de service peut se baser sur la réponse du fournisseur d’identité pour créer un contexte de sécurité, et ensuite accorder ou refuser l’accès à la ressource demandée initialement.</li>
</ol>
<h3>Premier pas dans Liferay</h3>
<p>Maintenant que l’on a une idée un peu plus claire de ce que l’on souhaite faire, regardons le portail Liferay, et essayons de comprendre comment fonctionnent ses mécanismes d’authentification. Liferay s’intègre déjà avec plusieurs solutions de SSO (dont notamment <a href="http://www.jasig.org/cas">CAS</a> et <a href="http://en.wikipedia.org/wiki/OpenSSO">OpenSSO</a> (voir aussi <a href="http://www.forgerock.com/openam.html">OpenAM</a>)) grâce au système d’AutoLogin.</p>
<p>La propriété « auto.login.hooks » du fichier portal.properties (qui peut être surchargé par le fichier portal-ext.properties à la racine du serveur Liferay, ou par plugin hook ou ext) contient une liste de classes qui implémentent l’interface AutoLogin, ces classes sont appelées successivement pour les utilisateurs non connectés jusqu&#8217;à ce que l’une d’entre elles renvoie un couple valide identifiant d’utilisateur et mot de passe. Dans ce cas, l’utilisateur sera automatiquement connecté au portail (Non, bien sûr ce n’est pas magique, pour plus de précision jetez un coup d’œil à la classe AutoLoginFilter). C’est aussi ainsi qu’est implémenté le « Remember me » (voir RememberMeAutoLogin qui fonctionne avec un cookie).</p>
<p>Nous allons donc créer une classe SAMLAutoLogin implémentant AutoLogin (comme c’est original…) :</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 /></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> com.<span style="color: #006633;">liferay</span>.<span style="color: #006633;">portal</span>.<span style="color: #006633;">security</span>.<span style="color: #006633;">auth</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #000000; font-weight: bold;">import</span> com.<span style="color: #006633;">liferay</span>.<span style="color: #006633;">portal</span>.<span style="color: #006633;">kernel</span>.<span style="color: #006633;">log</span>.<span style="color: #006633;">Log</span><span style="color: #339933;">;</span><br />
<span style="color: #000000; font-weight: bold;">import</span> com.<span style="color: #006633;">liferay</span>.<span style="color: #006633;">portal</span>.<span style="color: #006633;">kernel</span>.<span style="color: #006633;">log</span>.<span style="color: #006633;">LogFactoryUtil</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #000000; font-weight: bold;">import</span> javax.<span style="color: #006633;">servlet</span>.<span style="color: #006633;">http</span>.<span style="color: #006633;">HttpServletRequest</span><span style="color: #339933;">;</span><br />
<span style="color: #000000; font-weight: bold;">import</span> javax.<span style="color: #006633;">servlet</span>.<span style="color: #006633;">http</span>.<span style="color: #006633;">HttpServletResponse</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> SAMLAutoLogin <span style="color: #000000; font-weight: bold;">implements</span> AutoLogin <span style="color: #009900;">&#123;</span><br />
<br />
        @Override<br />
        <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #003399;">String</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> login<span style="color: #009900;">&#40;</span><br />
                        HttpServletRequest request, HttpServletResponse response<span style="color: #009900;">&#41;</span><br />
                <span style="color: #000000; font-weight: bold;">throws</span> AutoLoginException <span style="color: #009900;">&#123;</span><br />
<br />
                <span style="color: #666666; font-style: italic;">// TODO Auto-generated method stub</span><br />
<br />
                <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #339933;">;</span><br />
        <span style="color: #009900;">&#125;</span><br />
<br />
        <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">static</span> Log _log <span style="color: #339933;">=</span> LogFactoryUtil.<span style="color: #006633;">getLog</span><span style="color: #009900;">&#40;</span>SAMLAutoLogin.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div>
</pre>
<p>Si nous reprenons notre descriptif de l’échange, nous avons presque notre 1), en effet, l’AutoLogin va nous permettre de laisser le soin à Liferay de savoir quand est accédée une ressource protégée. Pour cela, il suffit de constater que lorsque l’utilisateur tente de lire un contenu restreint, le portail affiche le formulaire d’authentification par le biais d’une action Struts d’url « /portal/login », qui redirige vers la portlet Login (je suis sûr que vous ne vous attendiez pas à celle là), qui est une portlet Struts.</p>
<p>Avant de me mettre à répéter Struts sans arrêt, petite piqure de rappel, Liferay est basé sur Struts, et la majorité des portlets natives utilisent le bridge Struts de Liferay. Pour les curieux, ça se passe dans portlet-custom.xml (où se trouve portlet-class), liferay-portlet.xml (voir struts-path), et le classique struts-config.xml. Nous allons donc pouvoir, en testant la présence de « /portal/login/ » dans l’url, savoir que l’utilisateur doit se connecter, vous l’aurez peut-être remarqué, cette astuce fonctionne aussi si l’utilisateur utilise le lien de connexion.</p>
<p>Et là, <del>les petits malins</del> ceux qui sont attentifs se disent : « Lorsqu’on fait du SSO, l’objectif n’est pas de connecter automatiquement l’utilisateur déjà authentifié auprès du fournisseur d’identité dès qu’il arrive sur le site ? Sans qu’il ait besoin de cliquer sur le lien de connexion, ou qu’il ne tente de lire un document privé (qui ne devrait pas être affiché puisqu’il n’est pas connecté). », ce n’est pas faux, mais nous rectifierons plus tard.</p>
<p>Je rappelle (sait-on jamais) que voulant mettre en place une authentification unique, la portlet Login doit être bannie de vos pages…</p>
<h3>C’est fini pour aujourd’hui</h3>
<p>Nous voilà déjà arrivé à la fin de ce premier article, je vous ai présenté le mécanisme de l’authentification unique dans SAML, et nous avons commencé à l’intégrer dans un portail Liferay en interceptant les utilisateurs non connectés. Dans le prochain article, nous aborderons l’envoi de message via les « bindings ».</p>
<p>A bientôt pour de nouvelles aventures sur le blog Excilys…</p>
<p>&nbsp;</p>
<p><!--[if IE]><iframe frameborder="0" allowTransparency="true" class="addtoany_special_service twitter_tweet" src="http://platform.twitter.com/widgets/tweet_button.html?url=http%3A%2F%2Fblog.excilys.com%2F2011%2F09%2F26%2Fsaml-2-et-liferay-partie-1%2F&amp;counturl=http%3A%2F%2Fblog.excilys.com%2F2011%2F09%2F26%2Fsaml-2-et-liferay-partie-1%2F&amp;count=horizontal&amp;text=SAML%202%20et%20Liferay%20%26%238211%3B%20partie%201" scrolling="no" style="border:none;overflow:hidden;width:130px;height:20px"></iframe><![endif]--><!--[if !IE]><!--><iframe class="addtoany_special_service twitter_tweet" src="http://platform.twitter.com/widgets/tweet_button.html?url=http%3A%2F%2Fblog.excilys.com%2F2011%2F09%2F26%2Fsaml-2-et-liferay-partie-1%2F&amp;counturl=http%3A%2F%2Fblog.excilys.com%2F2011%2F09%2F26%2Fsaml-2-et-liferay-partie-1%2F&amp;count=horizontal&amp;text=SAML%202%20et%20Liferay%20%26%238211%3B%20partie%201" scrolling="no" style="border:none;overflow:hidden;width:130px;height:20px"></iframe><!--<![endif]--><!--[if IE]><iframe frameborder="0" allowTransparency="true" class="addtoany_special_service google_plusone" src="https://plusone.google.com/u/0/_/%2B1/fastbutton?url=http%3A%2F%2Fblog.excilys.com%2F2011%2F09%2F26%2Fsaml-2-et-liferay-partie-1%2F&amp;size=medium&amp;count=true" scrolling="no" style="border:none;overflow:hidden;width:90px;height:20px"></iframe><![endif]--><!--[if !IE]><!--><iframe class="addtoany_special_service google_plusone" src="https://plusone.google.com/u/0/_/%2B1/fastbutton?url=http%3A%2F%2Fblog.excilys.com%2F2011%2F09%2F26%2Fsaml-2-et-liferay-partie-1%2F&amp;size=medium&amp;count=true" scrolling="no" style="border:none;overflow:hidden;width:90px;height:20px"></iframe><!--<![endif]--><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fblog.excilys.com%2F2011%2F09%2F26%2Fsaml-2-et-liferay-partie-1%2F&amp;title=SAML%202%20et%20Liferay%20%26%238211%3B%20partie%201" id="wpa2a_18"><img src="http://blog.excilys.com/wp-content/plugins/add-to-any/share_save_120_16.png" width="120" height="16" alt="Share"/></a></p><img src="http://feeds.feedburner.com/~r/blogexcilyscom/~4/nR5ZJppUbfI" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.excilys.com/2011/09/26/saml-2-et-liferay-partie-1/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		<feedburner:origLink>http://blog.excilys.com/2011/09/26/saml-2-et-liferay-partie-1/</feedburner:origLink></item>
		<item>
		<title>Intégrer GWT dans Liferay : retour d’expérience</title>
		<link>http://feedproxy.google.com/~r/blogexcilyscom/~3/o9ihYAwACBI/</link>
		<comments>http://blog.excilys.com/2011/08/23/integrer-gwt-dans-liferay-retour-dexperience/#comments</comments>
		<pubDate>Tue, 23 Aug 2011 14:10:17 +0000</pubDate>
		<dc:creator>Alexandre DERGHAM</dc:creator>
				<category><![CDATA[Non classé]]></category>
		<category><![CDATA[google]]></category>
		<category><![CDATA[gwt]]></category>
		<category><![CDATA[gwt-rpc]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[JSP]]></category>
		<category><![CDATA[Liferay]]></category>
		<category><![CDATA[Liferay Portal]]></category>
		<category><![CDATA[Portal]]></category>
		<category><![CDATA[Servlet]]></category>

		<guid isPermaLink="false">http://blog.excilys.com/?p=3341</guid>
		<description><![CDATA[Au cour d&#8217;un projet, il m&#8217;a été demandé d&#8217;étudier la possibilité d&#8217;intégration d&#8217;une application GWT dans une portlet Liferay. Je vais vous présenter dans cet article la solution retenue. &#160; Une pointe de GWT dans un monde de JSP Pour rappel, une portlet comporte un ensemble de vues associées à des états. Pour afficher une [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.liferay.com"><img class="alignright 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>Au cour d&#8217;un projet, il m&#8217;a été demandé d&#8217;étudier la possibilité d&#8217;intégration d&#8217;une application GWT dans une portlet <a href="http://www.liferay.com/">Liferay</a>. Je vais vous présenter dans cet article la solution retenue.<br />
<span id="more-3341"></span><br />
&nbsp;</p>
<h3>Une pointe de GWT dans un monde de JSP</h3>
<p>Pour rappel, une portlet comporte un ensemble de vues associées à des états. Pour afficher une application GWT dans une portlet, il suffit de l’insérer dans les vues en question sous forme de widget. Dans notre exemple, nous travaillerons sur une vue implémentée en JSP.<br />
Dans une JSP d&#8217;une application web ordinaire, nous aurions écrit ceci :</p>
<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 /></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;script</span> <span style="color: #000066;">language</span>=<span style="color: #ff0000;">&quot;javascript&quot;</span> <span style="color: #000066;">src</span>=<span style="color: #ff0000;">&quot;myUI/myUI.nocache.js&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #000000; font-weight: bold;">&lt;/script<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;div</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;maDivAncrage&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #000000; font-weight: bold;">&lt;/div<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></td></tr></tbody></table></div>
<p>et le code java de notre entryPoint inclurait la ligne de code 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 /></div></td><td><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">RootPanel.<span style="color: #006633;">get</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;maDivAncrage&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">add</span><span style="color: #009900;">&#40;</span>monWidget<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></td></tr></tbody></table></div>
<p>Cependant, nous préférerons laisser à Liferay le soin d&#8217;importer les fichiers javascript et css dans la page qui abrite la portlet. Pour cela, nous déclarons l&#8217;import dans le fichier <em>liferay-portlet.xml</em> :</p>
<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 /></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;liferay-portlet-app<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;portlet<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;portlet-name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>myOtherPortlet<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/portlet-name<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;icon<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>/icon.png<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/icon<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;instanceable<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>false<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/instanceable<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;header-portlet-css<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>/css/myCss.css<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/header-portlet-css<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;footer-portlet-javascript<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>/myUI/myUI.nocache.js<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/footer-portlet-javascript<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;css-class-wrapper<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>myOtherPortlet-portlet<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/css-class-wrapper<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;/portlet<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
...<br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/liferay-portlet-app<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></td></tr></tbody></table></div>
<p>Le fichier JSP de notre vue ne contiendrait plus que la div.</p>
<p>&nbsp;</p>
<h3>Communiquer avec le back (in black) par ACD&#8230; non, je veux dire RPC</h3>
<p>Notre application GWT est désormais affichable dans une portlet. Nous devons maintenant lui faire afficher des données provenant du back-end et notamment des données associées à l&#8217;utilisateur actuellement connecté (donc dépendantes de la session HTTP en cours). Nous avons deux solutions possibles pour permettre au front-end de récupérer ces données :</p>
<ul>
<li>La première solution consiste à inscrire ces données dans la JSP en utilisant des scriptlets ou les taglibs de liferay (liferay-theme) pour ensuite les récupérer par <a href="http://code.google.com/intl/fr/webtoolkit/doc/latest/DevGuideCodingBasicsJSNI.html">JSNI</a>.</li>
<li>La seconde solution est la mise en place d&#8217;un service RPC entre le front et le back.</li>
</ul>
<p>Je ne détaillerais pas plus la première solution qui peut se révéler contraignante si on essaie de transporter des objets complexes et qui risque de faire intervenir du code métier dans la couche de présentation (notamment à cause des potentiels scriptlets).<BR /><br />
Nous allons donc mettre en place un service RPC. Cette solution est plus simple, plus standard et par conséquent plus facilement maintenable.<br />
Cependant, un problème va se poser au moment de récupérer la session HTTP. Notre implémentation de service est définie dans une servlet (<em>RemoteServiceServlet</em>) qui vit sa vie indépendamment du portail et n&#8217;a donc pas accès à une éventuelle HttpSession.</p>
<p>Pour répondre à ce problème, Liferay nous met à disposition la classe <em>PortalDelegateServlet</em> qui permet de partager (ou déléguer) les sessions du portail avec celles d&#8217;une autre servlet (en l&#8217;occurrence l&#8217;implémentation de notre service RPC). Pour cela, nous devons déclarer la servlet déléguée dans le fichier <em>web.xml</em> de notre portlet de la façon suivante :</p>
<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;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>myServlet<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>com.liferay.portal.kernel.servlet.PortalDelegateServlet<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;init-param<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;param-name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>servlet-class<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/param-name<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;param-value<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>com.excilys.liferay.server.MyServiceImpl<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/param-value<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;/init-param<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;init-param<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;param-name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>sub-context<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/param-name<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;param-value<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>mySubServlet<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/param-value<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;/init-param<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 />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/servlet<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></td></tr></tbody></table></div>
<p>Ensuite, nous redéfinissons dans la partie cliente de notre service l&#8217;url où contacter l&#8217;implémentation :</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 />5<br />6<br />7<br />8<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> MyUI <span style="color: #000000; font-weight: bold;">implements</span> EntryPoint <span style="color: #009900;">&#123;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> MyServiceAsync service <span style="color: #339933;">=</span> GWT.<span style="color: #006633;">create</span><span style="color: #009900;">&#40;</span>MyService.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; @Override<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> onModuleLoad<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: #009900;">&#40;</span><span style="color: #009900;">&#40;</span>ServiceDefTarget<span style="color: #009900;">&#41;</span> service<span style="color: #009900;">&#41;</span>.<span style="color: #006633;">setServiceEntryPoint</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;/delegate/mySubServlet&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; ...</div></td></tr></tbody></table></div>
<p>Enfin, dans l’implémentation de notre service RPC, il est possible d&#8217;accéder à la requête HTTP qui a permis l’affichage de la portlet grâce à la méthode getThreadLocalRequest de l&#8217;api GWT-RPC. Nous pouvons alors récupérer l&#8217;utilisateur actuellement connecté en utilisant la classe PortalUtil de l&#8217;api de Liferay.<br />
Notre implémentation ressemble à ceci :</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 />5<br />6<br />7<br />8<br />9<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> MyServiceImpl <span style="color: #000000; font-weight: bold;">extends</span> RemoteServiceServlet <span style="color: #000000; font-weight: bold;">implements</span> MyService <span style="color: #009900;">&#123;</span><br />
<br />
&nbsp; &nbsp; @Override<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #003399;">String</span> getCurrentUser<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;">String</span> userName <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #339933;">;</span><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; User user <span style="color: #339933;">=</span> PortalUtil.<span style="color: #006633;">getUser</span><span style="color: #009900;">&#40;</span>getThreadLocalRequest<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; userName <span style="color: #339933;">=</span> user.<span style="color: #006633;">getFullName</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ...</div></td></tr></tbody></table></div>
<p>&nbsp;</p>
<p>&nbsp;</p>
<h3>Serializable or IsSerialisable, that is the question</h3>
<p><img class="alignright size-full wp-image-3390" src="http://blog.excilys.com/wp-content/uploads/2011/06/shakespear.jpg" alt="" width="266" height="189" /><br />
Tant que le service RPC transmet des types simples, la solution décrite plus haut ne pose aucun problème. Malheureusement, si votre service envoie des objets (DTO) plus complexes, c&#8217;est une autre histoire.<br />
Le problème est que notre passage par le <em>PortalDelegateServlet</em> fausse le contextPath des requêtes et empêche GWT de charger le fichier définissant la politique de sérialisation. En conséquence, GWT utilise la politique par défaut qui consiste à ne supporter que les classes implémentant IsSerializable.<br />
Pour rappel, indépendamment de l&#8217;intégration dans Liferay, un objet DTO transmis par RPC doit implémenter les interfaces IsSerializable de l&#8217;API GWT ou Serialisable de java (depuis la version 1.4 de GWT) si la politique de sérialisation est correctement chargée.</p>
<p>Tout ceci ne nous laisse que deux options: </p>
<ul>
<li> Se résigner à utiliser l&#8217;interface IsSerializable qui reste spécifique à GWT.</li>
<li> Forcer le chargement de la politique de sérialisation en travaillant sur le contextPath manipulé par le service RPC.</li>
</ul>
<p>Dans notre cas et malgré les <a href="http://code.google.com/intl/fr/webtoolkit/doc/latest/FAQ_Server.html#Does_the_GWT_RPC_system_support_the_use_of_java.io.Serializable">recommandations de Google</a>, nous avons préféré implémenter <em>java.io.Serializable</em> (plus standard). Ainsi, pour contourner notre problème, j&#8217;ai réimplémenté la méthode doGetSerializationPolicy du service RPC :</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 />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 /></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> MyServiceImpl <span style="color: #000000; font-weight: bold;">extends</span> RemoteServiceServlet <span style="color: #000000; font-weight: bold;">implements</span> MyService <span style="color: #009900;">&#123;</span> &nbsp; &nbsp; &nbsp; &nbsp;<br />
&nbsp; &nbsp; ...<br />
&nbsp; &nbsp; @Override<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">protected</span> SerializationPolicy doGetSerializationPolicy<span style="color: #009900;">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; HttpServletRequest request, <span style="color: #003399;">String</span> moduleBaseURL, <span style="color: #003399;">String</span> strongName<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003399;">String</span> contextPath <span style="color: #339933;">=</span> request.<span style="color: #006633;">getContextPath</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: #003399;">String</span> modulePath <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>moduleBaseURL <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: #000000; font-weight: bold;">try</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; modulePath <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">URL</span><span style="color: #009900;">&#40;</span>moduleBaseURL<span style="color: #009900;">&#41;</span>.<span style="color: #006633;">getPath</span><span style="color: #009900;">&#40;</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> <span style="color: #000000; font-weight: bold;">catch</span> <span style="color: #009900;">&#40;</span><span style="color: #003399;">MalformedURLException</span> ex<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// log the information, we will default</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">log</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Malformed moduleBaseURL: &quot;</span> <span style="color: #339933;">+</span> moduleBaseURL, ex<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; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">/*<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;* Check that the module path must be in the same web app as the servlet<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;* itself. If you need to implement a scheme different than this, override<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;* this method.<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;*/</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>modulePath <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;">String</span> message <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;ERROR: The module path requested, &quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #339933;">+</span> modulePath<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #339933;">+</span> <span style="color: #0000ff;">&quot;, is not in the same web application as this servlet, &quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #339933;">+</span> contextPath<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #339933;">+</span> <span style="color: #0000ff;">&quot;. &nbsp;Your module may not be properly configured or your client and server code maybe out of date.&quot;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">log</span><span style="color: #009900;">&#40;</span>message<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;">else</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Strip off the context path from the module base URL. It should be a strict prefix.</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003399;">String</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> urlParts <span style="color: #339933;">=</span> modulePath.<span style="color: #006633;">split</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;/&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003399;">String</span> portletPath <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;&quot;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">if</span><span style="color: #009900;">&#40;</span>urlParts.<span style="color: #006633;">length</span> <span style="color: #339933;">&gt;</span> <span style="color: #cc66cc;">2</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; portletPath <span style="color: #339933;">=</span> urlParts<span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// we rebuild the moduleBaseURL because of differences of contextPath due to liferay's DelegatePortalServlet.</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; StringBuilder builder <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> StringBuilder<span style="color: #009900;">&#40;</span>moduleBaseURL<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">int</span> hostURLLength <span style="color: #339933;">=</span> moduleBaseURL.<span style="color: #006633;">length</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-</span>modulePath.<span style="color: #006633;">length</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">+</span> contextPath.<span style="color: #006633;">length</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; builder.<span style="color: #006633;">delete</span><span style="color: #009900;">&#40;</span>hostURLLength, hostURLLength <span style="color: #339933;">+</span> portletPath.<span style="color: #006633;">length</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">+</span> <span style="color: #cc66cc;">1</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; moduleBaseURL <span style="color: #339933;">=</span> builder.<span style="color: #006633;">toString</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000000; font-weight: bold;">super</span>.<span style="color: #006633;">doGetSerializationPolicy</span><span style="color: #009900;">&#40;</span>request, moduleBaseURL, strongName<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></div></td></tr></tbody></table></div>
<p>&nbsp;</p>
<h3>Le fin mot de l&#8217;histoire</h3>
<p>Intégrer GWT dans une portlet Liferay s&#8217;effectue aussi simplement que dans une page JSP. Il faut cependant tenir compte du partage de session du portail, du chargement des fichiers javascripts et css et de l&#8217;éventuel accès au contextPath. Notez que la portlet dans laquelle nous avons travaillé n&#8217;est pas instanciable et que les solutions énoncées ne seraient pas suffisantes pour faire fonctionner plusieurs instances d&#8217;une même portlet GWT dans une même page (notre div d&#8217;ancrage étant chargée 2 fois avec le même identifiant). Il existe des <a href="http://milen.commsen.com/2011/01/liferay-gwt-portlet-how-to-make-it-instanceable-and-use-gwt-rpc.html">solutions</a> pour remédier à cela mais je ne les ai pas mises en pratique.</p>
<p><!--[if IE]><iframe frameborder="0" allowTransparency="true" class="addtoany_special_service twitter_tweet" src="http://platform.twitter.com/widgets/tweet_button.html?url=http%3A%2F%2Fblog.excilys.com%2F2011%2F08%2F23%2Fintegrer-gwt-dans-liferay-retour-dexperience%2F&amp;counturl=http%3A%2F%2Fblog.excilys.com%2F2011%2F08%2F23%2Fintegrer-gwt-dans-liferay-retour-dexperience%2F&amp;count=horizontal&amp;text=Int%C3%A9grer%20GWT%20dans%20Liferay%20%3A%20retour%20d%26%238217%3Bexp%C3%A9rience" scrolling="no" style="border:none;overflow:hidden;width:130px;height:20px"></iframe><![endif]--><!--[if !IE]><!--><iframe class="addtoany_special_service twitter_tweet" src="http://platform.twitter.com/widgets/tweet_button.html?url=http%3A%2F%2Fblog.excilys.com%2F2011%2F08%2F23%2Fintegrer-gwt-dans-liferay-retour-dexperience%2F&amp;counturl=http%3A%2F%2Fblog.excilys.com%2F2011%2F08%2F23%2Fintegrer-gwt-dans-liferay-retour-dexperience%2F&amp;count=horizontal&amp;text=Int%C3%A9grer%20GWT%20dans%20Liferay%20%3A%20retour%20d%26%238217%3Bexp%C3%A9rience" scrolling="no" style="border:none;overflow:hidden;width:130px;height:20px"></iframe><!--<![endif]--><!--[if IE]><iframe frameborder="0" allowTransparency="true" class="addtoany_special_service google_plusone" src="https://plusone.google.com/u/0/_/%2B1/fastbutton?url=http%3A%2F%2Fblog.excilys.com%2F2011%2F08%2F23%2Fintegrer-gwt-dans-liferay-retour-dexperience%2F&amp;size=medium&amp;count=true" scrolling="no" style="border:none;overflow:hidden;width:90px;height:20px"></iframe><![endif]--><!--[if !IE]><!--><iframe class="addtoany_special_service google_plusone" src="https://plusone.google.com/u/0/_/%2B1/fastbutton?url=http%3A%2F%2Fblog.excilys.com%2F2011%2F08%2F23%2Fintegrer-gwt-dans-liferay-retour-dexperience%2F&amp;size=medium&amp;count=true" scrolling="no" style="border:none;overflow:hidden;width:90px;height:20px"></iframe><!--<![endif]--><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fblog.excilys.com%2F2011%2F08%2F23%2Fintegrer-gwt-dans-liferay-retour-dexperience%2F&amp;title=Int%C3%A9grer%20GWT%20dans%20Liferay%20%3A%20retour%20d%26%238217%3Bexp%C3%A9rience" id="wpa2a_20"><img src="http://blog.excilys.com/wp-content/plugins/add-to-any/share_save_120_16.png" width="120" height="16" alt="Share"/></a></p><img src="http://feeds.feedburner.com/~r/blogexcilyscom/~4/o9ihYAwACBI" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.excilys.com/2011/08/23/integrer-gwt-dans-liferay-retour-dexperience/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		<feedburner:origLink>http://blog.excilys.com/2011/08/23/integrer-gwt-dans-liferay-retour-dexperience/</feedburner:origLink></item>
	</channel>
</rss>

