<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Blog Technique d&#039;Infin-IT</title>
	<atom:link href="http://blog.infin-it.fr/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.infin-it.fr</link>
	<description>Le blog technique d&#039;Infin-It</description>
	<lastBuildDate>Thu, 13 Dec 2012 16:46:18 +0000</lastBuildDate>
	<language>fr-FR</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.8.4</generator>
	<item>
		<title>Maven : Integration Tests with SoapUI and Sonar Code Coverage</title>
		<link>http://blog.infin-it.fr/2012/12/13/maven-integration-tests-with-soapui-and-sonar-code-coverage/</link>
		<comments>http://blog.infin-it.fr/2012/12/13/maven-integration-tests-with-soapui-and-sonar-code-coverage/#comments</comments>
		<pubDate>Thu, 13 Dec 2012 16:46:18 +0000</pubDate>
		<dc:creator><![CDATA[Jean-Philippe Briend]]></dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Maven]]></category>
		<category><![CDATA[Sonar]]></category>
		<category><![CDATA[cobertura]]></category>
		<category><![CDATA[sonar]]></category>
		<category><![CDATA[sopaui]]></category>

		<guid isPermaLink="false">http://blog.infin-it.fr/?p=468</guid>
		<description><![CDATA[In this article, I will explain you how to add to your Maven build some Integration Tests executed by SoapUI. As a bonus, Sonar Code Coverage will be enhanced with these tests. Pre-requisites Maven 3 is required because some of the below plugins have this requirement. If you need to keep a Maven 2 build [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>In this article, I will explain you how to add to your <a title="Maven" href="http://maven.apache.org/" target="_blank">Maven</a> build some Integration Tests executed by <a href="http://www.soapui.org/" target="_blank">SoapUI</a>.</p>
<p>As a bonus, <a href="http://www.sonarsource.org/" target="_blank">Sonar</a> Code Coverage will be enhanced with these tests.</p>
<p><span id="more-468"></span><br />
<a href="http://blog.infin-it.fr/2012/12/13/maven-integration-tests-with-soapui-and-sonar-code-coverage/testing/" rel="attachment wp-att-471"><img class="aligncenter size-full wp-image-471" alt="Testing" src="http://blog.infin-it.fr/wp-content/uploads/2012/12/Testing.png" width="500" height="400" /></a></p>
<h3>Pre-requisites</h3>
<p><a href="http://blog.infin-it.fr/2012/12/13/maven-integration-tests-with-soapui-and-sonar-code-coverage/logo-maven-2/" rel="attachment wp-att-517"><img src="http://blog.infin-it.fr/wp-content/uploads/2012/12/logo-maven1.png" alt="logo-maven" width="320" height="90" class="aligncenter size-full wp-image-517" /></a></p>
<p>Maven 3 is required because some of the below plugins have this requirement.<br />
If you need to keep a Maven 2 build for your dev team, put all this configuration in a Maven profile dedicated to your Sonar build (ex: Profile <em>integration</em>).</p>
<h3>Explanations</h3>
<p>Here are the different plugins and configurations needed to succeed.</p>
<h4>Cobertura dependency</h4>
<pre class="brush: xml; title: ; notranslate">
&lt;dependencies&gt;
    &lt;!-- needed to execute Integration tests instrumented with Cobertura --&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;net.sourceforge.cobertura&lt;/groupId&gt;
        &lt;artifactId&gt;cobertura&lt;/artifactId&gt;
        &lt;version&gt;1.9.4&lt;/version&gt;
        &lt;scope&gt;test&lt;/scope&gt;
    &lt;/dependency&gt;
&lt;/dependencies&gt;
</pre>
<p>This dependency is needed in order to instrument the classes with <a href="http://cobertura.sourceforge.net/" target="_blank">Cobertura</a>.</p>
<h4>Maven SoapUI plugin</h4>
<p><a href="http://blog.infin-it.fr/2012/12/13/maven-integration-tests-with-soapui-and-sonar-code-coverage/soapui-logo/" rel="attachment wp-att-477"><img src="http://blog.infin-it.fr/wp-content/uploads/2012/12/Soapui-logo.png" alt="Soapui-logo" width="239" height="100" class="aligncenter size-full wp-image-477" /></a></p>
<p>The complete documentation for this plugin may be found here : <a href="http://www.soapui.org/Test-Automation/maven-2x.html" target="_blank">Maven SoapUI plugin</a>.</p>
<pre class="brush: xml; title: ; notranslate">
&lt;plugin&gt;
    &lt;groupId&gt;eviware&lt;/groupId&gt;
    &lt;artifactId&gt;maven-soapui-plugin&lt;/artifactId&gt;
    &lt;version&gt;4.5.1&lt;/version&gt;
    &lt;configuration&gt;
        &lt;junitReport&gt;true&lt;/junitReport&gt;
        &lt;exportAll&gt;true&lt;/exportAll&gt;
        &lt;projectFile&gt;${project.build.directory}/test-classes/my-soapui-project.xml&lt;/projectFile&gt;
        &lt;outputFolder&gt;${project.build.directory}/surefire-reports&lt;/outputFolder&gt;
        &lt;testSuite&gt;myIntegrationTests&lt;/testSuite&gt;
        &lt;testFailIgnore&gt;true&lt;/testFailIgnore&gt;
    &lt;/configuration&gt;
    &lt;executions&gt;
        &lt;execution&gt;
            &lt;id&gt;wsn-server-test&lt;/id&gt;
            &lt;phase&gt;integration-test&lt;/phase&gt;
            &lt;goals&gt;
                &lt;goal&gt;test&lt;/goal&gt;
            &lt;/goals&gt;
        &lt;/execution&gt;
    &lt;/executions&gt;
&lt;/plugin&gt;
</pre>
<p>This plugin will execute a SoapUI test suite contained in a SoapUI project XML file.<br />
If you want to filter (using Maven filtering) this file, use the projectFile property to load the project&#8217;s file from the target directory :</p>
<pre class="brush: xml; title: ; notranslate">
&lt;projectFile&gt;${project.build.directory}/test-classes/my-soapui-project.xml&lt;/projectFile&gt;
</pre>
<p>Property <em>testFailIgnore</em> must be set to <em>true</em> in order to prevent a failing test to break the build.</p>
<p>In this example, the plugin will execute the <em>myIntegrationTests</em> test suite from the project file <em>my-soapui-project.xml</em>.</p>
<p>The plugin <em>test</em> execution must be bound to the <em>integration-test</em> phase.</p>
<h4>Cobertura IT Maven plugin</h4>
<p>The <a href="http://code.google.com/p/cobertura-it-maven-plugin/" target="_blank">cobertura-it-maven-plugin</a> is a fork of codehaus <a href="http://mojo.codehaus.org/cobertura-maven-plugin" target="_blank">cobertura-maven-plugin</a> which enable the so long waited integration test coverage feature <a href="http://jira.codehaus.org/browse/MCOBERTURA-86" target="_blank">MCOBERTURA-86</a>.</p>
<pre class="brush: xml; title: ; notranslate">
&lt;plugin&gt;
    &lt;groupId&gt;org.codehaus.mojo&lt;/groupId&gt;
    &lt;artifactId&gt;cobertura-it-maven-plugin&lt;/artifactId&gt;
    &lt;version&gt;2.5&lt;/version&gt;
    &lt;configuration&gt;
        &lt;formats&gt;
            &lt;format&gt;xml&lt;/format&gt;
            &lt;format&gt;html&lt;/format&gt;
        &lt;/formats&gt;
        &lt;check&gt;
            &lt;haltOnFailure&gt;false&lt;/haltOnFailure&gt;
        &lt;/check&gt;
    &lt;/configuration&gt;
    &lt;executions&gt;
        &lt;execution&gt;
            &lt;id&gt;cobertura-clean&lt;/id&gt;
            &lt;phase&gt;clean&lt;/phase&gt;
            &lt;goals&gt;
                &lt;goal&gt;clean&lt;/goal&gt;
            &lt;/goals&gt;
        &lt;/execution&gt;
        &lt;execution&gt;
            &lt;id&gt;cobertura-instrument&lt;/id&gt;
            &lt;phase&gt;process-classes&lt;/phase&gt;
            &lt;goals&gt;
                &lt;goal&gt;instrument&lt;/goal&gt;
            &lt;/goals&gt;
        &lt;/execution&gt;
        &lt;execution&gt;
            &lt;id&gt;cobertura-report&lt;/id&gt;
            &lt;phase&gt;pre-site&lt;/phase&gt;
            &lt;goals&gt;
                &lt;goal&gt;report-only&lt;/goal&gt;
            &lt;/goals&gt;
        &lt;/execution&gt;
    &lt;/executions&gt;
&lt;/plugin&gt;
</pre>
<p>The XML output report is mandatory for the Sonar analysis. The HTML one may be used by the development team but it&#8217;s optional.</p>
<p>Do not forget to set <em>haltOnFailure</em> in order to prevent a test failure to stop the build.</p>
<p>3 executions must be defined :</p>
<ul>
<li>Goal <em>clean</em> must be called to clear instrumenting in the <em>clean</em> Maven phase.</li>
<li>Goal <em>instrument</em> must be executed in the <em>process-classes</em> in order to instrument the classes.</li>
<li>Goal <em>report-only</em> must be executed in the <em>pre-site</em> phase.</li>
</ul>
<p>Now, let&#8217;s configure a Jetty server to start just before integration test execution and stop just after them.</p>
<h4>Jetty Maven plugin</h4>
<p><a href="http://blog.infin-it.fr/2012/12/13/maven-integration-tests-with-soapui-and-sonar-code-coverage/jetty-logo-80x22/" rel="attachment wp-att-521"><img src="http://blog.infin-it.fr/wp-content/uploads/2012/12/jetty-logo-80x22.png" alt="jetty-logo-80x22" width="283" height="80" class="aligncenter size-full wp-image-521" /></a></p>
<p>Beware : this plugin must not be mixed with the maven-jetty-plugin.<br />
This one is the new one, respecting the Maven convetion naming.</p>
<p>The complete documentation may be found here : <a href="http://wiki.eclipse.org/Jetty/Feature/Jetty_Maven_Plugin" target="_blank">jetty-maven-plugin</a>.</p>
<pre class="brush: xml; title: ; notranslate">
&lt;plugin&gt;
    &lt;groupId&gt;org.mortbay.jetty&lt;/groupId&gt;
    &lt;artifactId&gt;jetty-maven-plugin&lt;/artifactId&gt;
    &lt;version&gt;8.1.2.v20120308&lt;/version&gt;
    &lt;configuration&gt;
        &lt;stopPort&gt;18043&lt;/stopPort&gt;
        &lt;stopKey&gt;STOP&lt;/stopKey&gt;
        &lt;connectors&gt;
            &lt;connector implementation=&quot;org.eclipse.jetty.server.nio.SelectChannelConnector&quot;&gt;
                &lt;port&gt;18042&lt;/port&gt;
            &lt;/connector&gt;
        &lt;/connectors&gt;
    &lt;/configuration&gt;
    &lt;executions&gt;
        &lt;execution&gt;
            &lt;id&gt;start-jetty&lt;/id&gt;
            &lt;phase&gt;pre-integration-test&lt;/phase&gt;
            &lt;goals&gt;
                &lt;goal&gt;start&lt;/goal&gt;
            &lt;/goals&gt;
            &lt;configuration&gt;
                &lt;!-- Needed in order to to code coverage on SoapUI tests --&gt;
                &lt;classesDirectory&gt;${project.build.directory}/generated-classes/cobertura&lt;/classesDirectory&gt;
                &lt;useTestScope&gt;true&lt;/useTestScope&gt;
                &lt;scanIntervalSeconds&gt;0&lt;/scanIntervalSeconds&gt;
                &lt;daemon&gt;true&lt;/daemon&gt;
                &lt;contextPath&gt;/myIntegrationTestsContext&lt;/contextPath&gt;
            &lt;/configuration&gt;
        &lt;/execution&gt;
        &lt;execution&gt;
            &lt;id&gt;stop-jetty&lt;/id&gt;
            &lt;phase&gt;post-integration-test&lt;/phase&gt;
            &lt;goals&gt;
                &lt;goal&gt;stop&lt;/goal&gt;
            &lt;/goals&gt;
        &lt;/execution&gt;
    &lt;/executions&gt;
&lt;/plugin&gt;
</pre>
<p>Attribute <em>classesDirectory</em> must be specified to use the instrumented classes.</p>
<p>The goal <em>start</em> is a new one introduced by the new version of the Jetty plugin. It starts a Jetty server without first executing the build up to &#8220;test-compile&#8221; phase.<br />
Do not forget to set the attribute <em><daemon>true</daemon></em> in order to force Jetty to execute only while Maven is running, instead of running indefinitely.</p>
<p>Maven phases <em>pre-integration-test</em> and <em>post-integration-test</em> are used to start and stop the Jetty server.</p>
<h4>Reporting</h4>
<p>The reporting phase is mandatory to generate the Cobertura report. A bug prevents the Cobertura report to be generated in the integration-test phase.</p>
<pre class="brush: xml; title: ; notranslate">
&lt;reporting&gt;
    &lt;plugins&gt;
        &lt;plugin&gt;
            &lt;groupId&gt;org.codehaus.mojo&lt;/groupId&gt;
            &lt;artifactId&gt;cobertura-it-maven-plugin&lt;/artifactId&gt;
            &lt;version&gt;2.5&lt;/version&gt;
            &lt;configuration&gt;
                &lt;formats&gt;
                    &lt;format&gt;html&lt;/format&gt;
                    &lt;format&gt;xml&lt;/format&gt;
                &lt;/formats&gt;
            &lt;/configuration&gt;
            &lt;reportSets&gt;
                &lt;reportSet&gt;
                    &lt;reports&gt;
                        &lt;report&gt;report-only&lt;/report&gt;
                    &lt;/reports&gt;
                &lt;/reportSet&gt;
            &lt;/reportSets&gt;
        &lt;/plugin&gt;
    &lt;/plugins&gt;
&lt;/reporting&gt;
</pre>
<h4>Sonar configuration</h4>
<p>In order to make Sonar reuse reports, configure these properties in your Maven build :</p>
<pre class="brush: xml; title: ; notranslate">

&lt;sonar.dynamicAnalysis&gt;reuseReports&lt;/sonar.dynamicAnalysis&gt;
&lt;sonar.surefire.reportsPath&gt;${project.build.directory}/surefire-reports&lt;/sonar.surefire.reportsPath&gt;
&lt;sonar.cobertura.reportPath&gt;${project.build.directory}/site/cobertura/coverage.xml&lt;/sonar.cobertura.reportPath&gt;

</pre>
<h3>Jenkins configuration</h3>
<p>A quite special configuration must be done in your Jenkins build : a Post Step must be added.<br />
This step must launch <em>mvn site</em> command in order to produce the Cobertura report.</p>
<p><a href="http://blog.infin-it.fr/2012/12/13/maven-integration-tests-with-soapui-and-sonar-code-coverage/maven-it/" rel="attachment wp-att-512"><img src="http://blog.infin-it.fr/wp-content/uploads/2012/12/maven-IT.jpg" alt="maven-IT" width="985" height="421" class="aligncenter size-full wp-image-512" /></a></p>
<p><a href="http://blog.infin-it.fr/2012/12/13/maven-integration-tests-with-soapui-and-sonar-code-coverage/maven-it-2/" rel="attachment wp-att-511"><img src="http://blog.infin-it.fr/wp-content/uploads/2012/12/maven-IT-2.jpg" alt="maven-IT-2" width="1005" height="303" class="aligncenter size-full wp-image-511" /></a></p>
<h3>Complete code</h3>
<pre class="brush: xml; title: ; notranslate">
&lt;dependencies&gt;
    &lt;!-- needed to execute Integration tests instrumented with Cobertura --&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;net.sourceforge.cobertura&lt;/groupId&gt;
        &lt;artifactId&gt;cobertura&lt;/artifactId&gt;
        &lt;version&gt;1.9.4&lt;/version&gt;
        &lt;scope&gt;test&lt;/scope&gt;
    &lt;/dependency&gt;
&lt;/dependencies&gt;
&lt;build&gt;
    &lt;plugins&gt;
        &lt;plugin&gt;
            &lt;groupId&gt;eviware&lt;/groupId&gt;
            &lt;artifactId&gt;maven-soapui-plugin&lt;/artifactId&gt;
            &lt;version&gt;4.5.1&lt;/version&gt;
            &lt;configuration&gt;
                &lt;junitReport&gt;true&lt;/junitReport&gt;
                &lt;exportAll&gt;true&lt;/exportAll&gt;
                &lt;projectFile&gt;${project.build.directory}/test-classes/my-soapui-project.xml&lt;/projectFile&gt;
                &lt;outputFolder&gt;${project.build.directory}/surefire-reports&lt;/outputFolder&gt;
                &lt;testSuite&gt;myIntegrationTests&lt;/testSuite&gt;
                &lt;testFailIgnore&gt;true&lt;/testFailIgnore&gt;
            &lt;/configuration&gt;
            &lt;executions&gt;
                &lt;execution&gt;
                    &lt;id&gt;wsn-server-test&lt;/id&gt;
                    &lt;phase&gt;integration-test&lt;/phase&gt;
                    &lt;goals&gt;
                        &lt;goal&gt;test&lt;/goal&gt;
                    &lt;/goals&gt;
                &lt;/execution&gt;
            &lt;/executions&gt;
        &lt;/plugin&gt;
        &lt;plugin&gt;
            &lt;groupId&gt;org.codehaus.mojo&lt;/groupId&gt;
            &lt;artifactId&gt;cobertura-it-maven-plugin&lt;/artifactId&gt;
            &lt;version&gt;2.5&lt;/version&gt;
            &lt;configuration&gt;
                &lt;formats&gt;
                    &lt;format&gt;xml&lt;/format&gt;
                    &lt;format&gt;html&lt;/format&gt;
                &lt;/formats&gt;
                &lt;check&gt;
                    &lt;haltOnFailure&gt;false&lt;/haltOnFailure&gt;
                &lt;/check&gt;
            &lt;/configuration&gt;
            &lt;executions&gt;
                &lt;execution&gt;
                    &lt;id&gt;cobertura-clean&lt;/id&gt;
                    &lt;phase&gt;clean&lt;/phase&gt;
                    &lt;goals&gt;
                        &lt;goal&gt;clean&lt;/goal&gt;
                    &lt;/goals&gt;
                &lt;/execution&gt;
                &lt;execution&gt;
                    &lt;id&gt;cobertura-instrument&lt;/id&gt;
                    &lt;phase&gt;process-classes&lt;/phase&gt;
                    &lt;goals&gt;
                        &lt;goal&gt;instrument&lt;/goal&gt;
                    &lt;/goals&gt;
                &lt;/execution&gt;
                &lt;execution&gt;
                    &lt;id&gt;cobertura-report&lt;/id&gt;
                    &lt;phase&gt;pre-site&lt;/phase&gt;
                    &lt;goals&gt;
                        &lt;goal&gt;report-only&lt;/goal&gt;
                    &lt;/goals&gt;
                &lt;/execution&gt;
            &lt;/executions&gt;
        &lt;/plugin&gt;
        &lt;plugin&gt;
            &lt;groupId&gt;org.mortbay.jetty&lt;/groupId&gt;
            &lt;artifactId&gt;jetty-maven-plugin&lt;/artifactId&gt;
            &lt;version&gt;8.1.2.v20120308&lt;/version&gt;
            &lt;configuration&gt;
                &lt;stopPort&gt;18043&lt;/stopPort&gt;
                &lt;stopKey&gt;STOP&lt;/stopKey&gt;
                &lt;connectors&gt;
                    &lt;connector implementation=&quot;org.eclipse.jetty.server.nio.SelectChannelConnector&quot;&gt;
                        &lt;port&gt;18042&lt;/port&gt;
                    &lt;/connector&gt;
                &lt;/connectors&gt;
            &lt;/configuration&gt;
            &lt;executions&gt;
                &lt;execution&gt;
                    &lt;id&gt;start-jetty&lt;/id&gt;
                    &lt;phase&gt;pre-integration-test&lt;/phase&gt;
                    &lt;goals&gt;
                        &lt;goal&gt;start&lt;/goal&gt;
                    &lt;/goals&gt;
                    &lt;configuration&gt;
                        &lt;!-- Needed in order to to code coverage on SoapUI tests --&gt;
                        &lt;classesDirectory&gt;${project.build.directory}/generated-classes/cobertura&lt;/classesDirectory&gt;
                        &lt;useTestScope&gt;true&lt;/useTestScope&gt;
                        &lt;scanIntervalSeconds&gt;0&lt;/scanIntervalSeconds&gt;
                        &lt;daemon&gt;true&lt;/daemon&gt;
                        &lt;contextPath&gt;/myIntegrationTestsContext&lt;/contextPath&gt;
                    &lt;/configuration&gt;
                &lt;/execution&gt;
                &lt;execution&gt;
                    &lt;id&gt;stop-jetty&lt;/id&gt;
                    &lt;phase&gt;post-integration-test&lt;/phase&gt;
                    &lt;goals&gt;
                        &lt;goal&gt;stop&lt;/goal&gt;
                    &lt;/goals&gt;
                &lt;/execution&gt;
            &lt;/executions&gt;
        &lt;/plugin&gt;
    &lt;/plugins&gt;
&lt;/build&gt;
&lt;reporting&gt;
    &lt;plugins&gt;
        &lt;plugin&gt;
            &lt;groupId&gt;org.codehaus.mojo&lt;/groupId&gt;
            &lt;artifactId&gt;cobertura-it-maven-plugin&lt;/artifactId&gt;
            &lt;version&gt;2.5&lt;/version&gt;
            &lt;configuration&gt;
                &lt;formats&gt;
                    &lt;format&gt;html&lt;/format&gt;
                    &lt;format&gt;xml&lt;/format&gt;
                &lt;/formats&gt;
            &lt;/configuration&gt;
            &lt;reportSets&gt;
                &lt;reportSet&gt;
                    &lt;reports&gt;
                        &lt;report&gt;report-only&lt;/report&gt;
                    &lt;/reports&gt;
                &lt;/reportSet&gt;
            &lt;/reportSets&gt;
        &lt;/plugin&gt;
    &lt;/plugins&gt;
&lt;/reporting&gt;
</pre>
<h3>Complement</h3>
<p>Here is another article dealing with Integration Tests in Maven builds : <a href="http://antoniogoncalves.org/2012/12/13/lets-turn-integration-tests-with-maven-to-a-first-class-citizen/" target="_blank">Let’s Turn Integration Tests with Maven to a First-Class Citizen</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.infin-it.fr/2012/12/13/maven-integration-tests-with-soapui-and-sonar-code-coverage/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Sonar DotNet Gallio : An attempt was made to load a program with an incorrect format.</title>
		<link>http://blog.infin-it.fr/2012/10/29/sonar-dotnet-gallio-an-attempt-was-made-to-load-a-program-with-an-incorrect-format/</link>
		<comments>http://blog.infin-it.fr/2012/10/29/sonar-dotnet-gallio-an-attempt-was-made-to-load-a-program-with-an-incorrect-format/#comments</comments>
		<pubDate>Mon, 29 Oct 2012 15:37:54 +0000</pubDate>
		<dc:creator><![CDATA[Jean-Philippe Briend]]></dc:creator>
				<category><![CDATA[Sonar]]></category>
		<category><![CDATA[dotnet]]></category>
		<category><![CDATA[gallio]]></category>
		<category><![CDATA[plugin]]></category>
		<category><![CDATA[sonar]]></category>

		<guid isPermaLink="false">http://blog.infin-it.fr/?p=454</guid>
		<description><![CDATA[When using the sonar-csharp-core-plugin with Gallio (for executing Unit Tests), you may encounter the following error An attempt was made to load a program with an incorrect format: After many attempts, I found the error : the build was being executed on a 64bits machine while the build was a 32bits. The solution is to [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>When using the <a href="http://docs.codehaus.org/display/SONAR/sonar-csharp-gallio-plugin" target="_blank">sonar-csharp-core-plugin</a> with Gallio (for executing Unit Tests), you may encounter the following error <strong>An attempt was made to load a program with an incorrect format</strong>:</p>
<pre class="brush: plain; title: ; notranslate">
[INFO] Running the tests.
[INFO] A fatal exception occurred while running tests.  Possible causes include invalid test runner parameters and stack overflows.
[INFO] 	Gallio.Model.ModelException: An exception occurred while invoking a test driver. ---&gt; Gallio.Model.ModelException: Gallio.Model.ModelException: Could not load test assembly from 'X:\XXXXX\MyDLL.dll'. ---&gt; System.BadImageFormatException: Could not load file or assembly 'file:///X:\XXXXX\MyDLL.dll' or one of its dependencies. An attempt was made to load a program with an incorrect format.
[INFO] 	   at System.Reflection.RuntimeAssembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark&amp; stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
[INFO] 	   at System.Reflection.RuntimeAssembly.nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark&amp; stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
[INFO] 	   at System.Reflection.RuntimeAssembly.InternalLoadAssemblyName(AssemblyName assemblyRef, Evidence assemblySecurity, StackCrawlMark&amp; stackMark, Boolean forIntrospection, Boolean suppressSecurityChecks)
[INFO] 	   at System.Reflection.RuntimeAssembly.InternalLoadFrom(String assemblyFile, Evidence securityEvidence, Byte[] hashValue, AssemblyHashAlgorithm hashAlgorithm, Boolean forIntrospection, Boolean suppressSecurityChecks, StackCrawlMark&amp; stackMark)
[INFO] 	   at System.Reflection.Assembly.LoadFrom(String assemblyFile)
[INFO] 	   at Gallio.Runtime.Loader.DefaultAssemblyLoader.LoadAssemblyFrom(String assemblyFile) in c:\Server\Projects\MbUnit v3.3\Work\src\Gallio\Gallio\Runtime\Loader\DefaultAssemblyLoader.cs:line 86
[INFO] 	   at Gallio.Model.DotNetTestDriver.ExploreOrRunTask.LoadAssembly(String assemblyPath) in c:\Server\Projects\MbUnit v3.3\Work\src\Gallio\Gallio\Model\DotNetTestDriver.cs:line 330
[INFO] 	   --- End of inner exception stack trace ---
[INFO] 	   at Gallio.Model.DotNetTestDriver.ExploreOrRunTask.LoadAssembly(String assemblyPath) in c:\Server\Projects\MbUnit v3.3\Work\src\Gallio\Gallio\Model\DotNetTestDriver.cs:line 337
</pre>
<p>After many attempts, I found the error : the build was being executed on a 64bits machine while the build was a 32bits.<br />
The solution is to change the <strong>sonar.gallio.runner</strong> parameter :</p>
<pre class="brush: plain; title: ; notranslate">
 
    &lt;sonar.gallio.runner&gt;IsolatedProcess&lt;/sonar.gallio.runner&gt;
 
</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.infin-it.fr/2012/10/29/sonar-dotnet-gallio-an-attempt-was-made-to-load-a-program-with-an-incorrect-format/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Persister ses dates avec JodaTime</title>
		<link>http://blog.infin-it.fr/2012/07/03/persister-ses-dates-avec-jodatime/</link>
		<comments>http://blog.infin-it.fr/2012/07/03/persister-ses-dates-avec-jodatime/#comments</comments>
		<pubDate>Tue, 03 Jul 2012 22:34:31 +0000</pubDate>
		<dc:creator><![CDATA[Jean-Philippe Briend]]></dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[JPA]]></category>
		<category><![CDATA[Maven]]></category>
		<category><![CDATA[Play!]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[joda time]]></category>
		<category><![CDATA[persistence]]></category>
		<category><![CDATA[play!]]></category>

		<guid isPermaLink="false">http://blog.infin-it.fr/?p=412</guid>
		<description><![CDATA[Joda Time est une librairie destinée à remplacer les classes Date et Time du JDK. Date et Time ont très peu évolué depuis le début du JDK, elles sont maintenant assez pénibles à utiliser sans devoir toujours re-coder les mêmes utilitaires. Que la Force soit avec nous C&#8217;est là que Joda Time intervient : Joda [&#8230;]]]></description>
				<content:encoded><![CDATA[<p><a href="http://joda-time.sourceforge.net/" target="_blank">Joda Time</a> est une librairie destinée à remplacer les classes Date et Time du JDK.<br />
Date et Time ont très peu évolué depuis le début du JDK, elles sont maintenant assez pénibles à utiliser sans devoir toujours re-coder les mêmes utilitaires.</p>
<p><a href="http://blog.infin-it.fr/wp-content/uploads/2012/07/master_joda.png"><img class="aligncenter size-full wp-image-418" title="Master Joda" src="http://blog.infin-it.fr/wp-content/uploads/2012/07/master_joda.png" alt="" width="256" height="256" /></a></p>
<p><span id="more-412"></span></p>
<h3>Que la Force soit avec nous</h3>
<p>C&#8217;est là que <a href="http://joda-time.sourceforge.net/" target="_blank">Joda Time</a> intervient :</p>
<ul>
<li>Joda Time est facile à utiliser grâce à des méthodes simples : par exemple <em>getYear()</em> ou <em>getDayOfWeek()</em>.</li>
<li>L&#8217;implémentation des TimeZones se base sur la base de données publique. Les releases de Joda Time incorporent les mises à jour de cette base de données.</li>
<li>8 systèmes de calendrier.</li>
<li>L&#8217;interopérabilité avec le JDK est simplifiée : la librairie utilise en interne la milliseconde, ce qui la rend facile interopérable avec les classes du JDK.</li>
<li>Des calculs simplifiés : il est très facile de rajouter ou enlever une durée à une date.</li>
<li>Joda Time est open source : sous licence.</li>
</ul>
<p>La <a href="http://joda-time.sourceforge.net/userguide.html" target="_blank">documentation</a> est très complète et la <a href="http://joda-time.sourceforge.net/api-release/index.html" target="_blank">Javadoc</a> complète le reste de l&#8217;API.</p>
<h3>Persistence de DateTime</h3>
<p>Intéressons nous à la persistence d&#8217;une des classes de Joda Time : <a href="http://joda-time.sourceforge.net/api-release/index.html" target="_blank">org.joda.time.DateTime</a>.</p>
<p>DateTime sert à représenter une date avec une précision de la milliseconde. Il s&#8217;agit d&#8217;une des classes les plus utilisées dans la librairie Joda Time. De plus, elle est <em>thread-safe</em> et <em>immutable</em>.</p>
<p>Le projet <a href="http://usertype.sourceforge.net/" title="Usertype for Hibernate Parent" target="_blank">Usertype for Hibernate Parent</a> offre un moyen de persister en base de données via <a href="http://www.hibernate.org/">Hibernate</a> (version 4.0 minimum) une instance de DateTime dans une colonne de type Date. Il s&#8217;agit du seul moyen de persister des objets Joda Time pour les versions supérieures à 2.x.</p>
<h3>Du côté de Maven</h3>
<p>Il faut tout d&#8217;abord ajouter les dépendances Joda Time et UserType à votre pom Maven :</p>
<pre class="brush: xml; title: ; notranslate">
&lt;dependency&gt;
    &lt;groupId&gt;joda-time&lt;/groupId&gt;
    &lt;artifactId&gt;joda-time&lt;/artifactId&gt;
    &lt;version&gt;2.1&lt;/version&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
    &lt;groupId&gt;org.jadira.usertype&lt;/groupId&gt;
    &lt;artifactId&gt;usertype.core&lt;/artifactId&gt;
    &lt;version&gt;3.0.0.CR1&lt;/version&gt;
&lt;/dependency&gt;
</pre>
<p>Il suffit maintenant d&#8217;utiliser la classe DateTime comme attribut d&#8217;une entité Hibernate et de l&#8217;annoter avec UserType pour pouvoir la persister :</p>
<pre class="brush: java; title: ; notranslate">
    ...
    @Column
    @Temporal(TemporalType.DATETIME)
    @Type(type=&quot;org.jadira.usertype.dateandtime.joda.PersistentDateTime&quot;)
    public DateTime date;
    ...
</pre>
<h3>Du côté de Play! Framework 1.x</h3>
<p>Attention : depuis la version 1.2.4 du framework Play!, Joda Time a été upgradé en version 2.x. Cet article traite de la seule façon de persister des objets Joda Time pour la librairie > 2.x.</p>
<p>Pour une application utilisant le framework Play! (> 1.2.4), il suffit de déclarer les dépendances dans son fichier <em>dependencies.yml</em> :</p>
<pre class="brush: java; title: ; notranslate">
require:
    ...
    - org.jadira.usertype -&gt; usertype.core 3.0.0.CR1:
        exclude:
          org.joda -&gt; joda-money
    ...
</pre>
<p>Le code Java de l&#8217;entité reste inchangé :</p>
<pre class="brush: java; title: ; notranslate">
    ...
    @Column
    @Temporal(TemporalType.DATETIME)
    @Type(type=&quot;org.jadira.usertype.dateandtime.joda.PersistentDateTime&quot;)
    public DateTime date;
    ...
</pre>
<p>Adaptez votre @Temporal en fonction de la précision souhaitée pour la colonne dans votre base de données.</p>
<h3>Le code mort tu supprimeras !</h3>
<p>Vous pouvez maintenant supprimer toutes vos classes DateUtils et supprimer le code mort qui servait à faire des conversions de dates à tout va !</p>
<p>Rappelez-vous : du code mort est du code supprimé !</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.infin-it.fr/2012/07/03/persister-ses-dates-avec-jodatime/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Se connecter à un serveur SFTP en Java</title>
		<link>http://blog.infin-it.fr/2012/02/10/se-connecter-a-un-serveur-sftp-en-java/</link>
		<comments>http://blog.infin-it.fr/2012/02/10/se-connecter-a-un-serveur-sftp-en-java/#comments</comments>
		<pubDate>Fri, 10 Feb 2012 17:20:16 +0000</pubDate>
		<dc:creator><![CDATA[Jean-Philippe Briend]]></dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[jsch]]></category>
		<category><![CDATA[sftp]]></category>
		<category><![CDATA[ssh]]></category>

		<guid isPermaLink="false">http://blog.infin-it.fr/?p=391</guid>
		<description><![CDATA[Travaillant sur des projets dans un environnement financier, beaucoup de transferts se font de manière sécurisée. Parmi eux, on retrouve très souvent les transferts de fichiers, habituellement rencontrés sur le protocole FTP. Or le protocole FTP n&#8217;est absolument pas sécurisé (données et mots de passe qui transitent en clair sur le réseau). Le choix opérationnel [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Travaillant sur des projets dans un environnement financier, beaucoup de transferts se font de manière sécurisée.</p>
<p>Parmi eux, on retrouve très souvent les transferts de fichiers, habituellement rencontrés sur le protocole FTP. Or le protocole FTP n&#8217;est absolument pas sécurisé (données et mots de passe qui transitent en clair sur le réseau).</p>
<p>Le choix opérationnel se porte très souvent sur SFTP.<br />
SFTP (SSH File Transfer Protocol), n&#8217;est pas FTP exécuté sur SSH, mais plutôt un nouveau protocole conçu dès le départ par le groupe de travail IETF SECSH.<br />
STFP est un protocole de communication fonctionnant au-dessus de SSH à ne pas confondre avec File Transfer Protocol over SSL, abrégé FTPS.</p>
<p>L&#8217;objectif de cet article est d&#8217;écrire un bout de code pour se connecter à un serveur SFTP, uploader un fichier et télécharger un fichier.<br />
Nous allons bien évidemment écrire un test unitaire et pour cela nous allons utiliser un serveur SFTP embarqué en mémoire.</p>
<p><span id="more-391"></span></p>
<h1>Le client : Jsch</h1>
<p><a href="http://www.jcraft.com/jsch/" title="Jsch" target="_blank">Jsch</a> est une implémentation 100% Java de <a href="http://ietf.org/html.charters/secsh-charter.html" title="SSH2" target="_blank">SSH2</a>.</p>
<p>Cette librairie va nous permettre de communiquer avec un serveur SFTP.<br />
L&#8217;authentification avec ce type de serveur peut se faire de 2 façons (n&#8217;oubliez pas que SFTP est du SSH, on retrouve donc beaucoup de choses en commun) :</p>
<ul>
<li>1 login et 1 mot de passe.</li>
<li>1 login et 1 clé privée (dont la clé publique est enregistrée sur le serveur auparavant).</li>
</ul>
<p>Dans cet article, nous utiliserons l&#8217;authentification par login/password (pour sa simplicité d&#8217;implémentation).</p>
<h3>Un serveur SFTP pour les développements locaux</h3>
<p>Pour les développements, je vous suggère d&#8217;utiliser un petit serveur SFTP à lancer sur votre poste :<br />
<a href="https://github.com/jpbriend/sftp-example/blob/master/src/main/resources/miniSFTPserver.exe" title="miniSFTPServer" target="_blank">miniSFTPServer</a> est un mini-serveur SFTP ultra-léger vous permettant de travailler en local.</p>
<p>Il suffit de le lancer, puis de configurer un port, un login, un mot de passe et un chemin root pour le serveur.</p>
<p><a href="http://blog.infin-it.fr/wp-content/uploads/2012/02/miniSFTPServer.png"><img src="http://blog.infin-it.fr/wp-content/uploads/2012/02/miniSFTPServer-300x272.png" alt="" title="miniSFTPServer" width="300" height="272" class="aligncenter size-medium wp-image-396" /></a></p>
<h3>La connection SFTP</h3>
<p>Maintenant que le serveur SFTP est up&#038;running en local, nous pouvons rentrer dans le vif du sujet.</p>
<p>La connection au serveur se fait sans encombre :</p>
<pre class="brush: java; title: ; notranslate">
jsch = new JSch();
session = jsch.getSession(login, server, port);

// Java 6 version
session.setPassword(password.getBytes(Charset.forName(&quot;ISO-8859-1&quot;)));
            
// Java 5 version
// session.setPassword(password.getBytes(&quot;ISO-8859-1&quot;));

Properties config = new java.util.Properties();
config.put(&quot;StrictHostKeyChecking&quot;, &quot;no&quot;);
session.setConfig(config);

session.connect();
</pre>
<p>Il faut ensuite rajouter un <strong>com.jcraft.jsch.Channel</strong> de type &#8220;sftp&#8221; (qui est un <strong>com.jcraft.jsch.ChannelSftp</strong> une fois le channel accepté) :</p>
<pre class="brush: java; title: ; notranslate">
// Initializing a channel
channel = session.openChannel(&quot;sftp&quot;);
channel.connect();
c = (ChannelSftp) channel;
</pre>
<h3>L&#8217;upload de fichier</h3>
<p>C&#8217;est encore tout simple : le Channel précédemment créé nous propose une méthode <strong>put</strong> :</p>
<pre class="brush: java; title: ; notranslate">
c.put(sourceFile, destinationFile);
</pre>
<p>Il s&#8217;agit ici de la version prenant 2 Strings en paramètres. Cette méthode existe en une foultitude de déclinaisons, je vous invite à regarder la Javadoc pour coller à vos besoins.</p>
<h3>Le téléchargement de fichier</h3>
<p>Même chose que précédemment : le Channel propose une méthode <strong>get</strong> :</p>
<pre class="brush: java; title: ; notranslate">
c.get(sourceFile, destinationFile);
</pre>
<h3>La déconnection</h3>
<p>Comme tout flux en Java, il est important de fermer le Channel puis la Session pour se déconnecter proprement !</p>
<h1>Le test unitaire : Mina SSHD</h1>
<p>Le projet <a href="http://mina.apache.org/" title="Mina" target="_blank">Mina</a> propose un sous-module très intéressant pour les tests unitaires de serveurs SFTP : <a href="http://mina.apache.org/sshd/" title="SSHD" target="_blank">SSHD</a>.</p>
<p>Nous allons utiliser SSHD pour démarrer un serveur SFTP en mémoire qui nous servira à tester notre client SFTP écrit précédemment.</p>
<h3>@Before</h3>
<p>Dans une méthode setUp (annotée en @Before), nous allons démarrer un <strong>org.apache.sshd.SshServer</strong>:</p>
<pre class="brush: java; title: ; notranslate">
@Before
public void setUp() throws IOException {
    // Init sftp server stuff
    sshd = SshServer.setUpDefaultServer();
    sshd.setPort(port);
    sshd.setPasswordAuthenticator(new MyPasswordAuthenticator());
    sshd.setPublickeyAuthenticator(new MyPublickeyAuthenticator());
    sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider());
    sshd.setSubsystemFactories(Arrays.&lt;NamedFactory&lt;Command&gt;&gt;asList(new SftpSubsystem.Factory()));
    sshd.setCommandFactory(new ScpCommandFactory());

    sshd.start();
    ...
    ...
}
</pre>
<p>La méthode setUpDefaultServer() préconfigure automatiquement le SshServer.<br />
Il ne reste qu&#8217;à rajouter le port d&#8217;écoute, implémenter un PasswordAuthenticator très simple, ainsi qu&#8217;un PublicKeyAuthenticator.</p>
<p>La partie touchy est la suivante : rajouter un ChannelSftp n&#8217;est pas trivial :</p>
<pre class="brush: java; title: ; notranslate">
sshd.setSubsystemFactories(Arrays.&lt;NamedFactory&lt;Command&gt;&gt;asList(new SftpSubsystem.Factory()));
</pre>
<p>Une fois le serveur démarré, le test unitaire est très facile à écrire.</p>
<h3>@After</h3>
<p>N&#8217;oubliez pas d&#8217;éteindre le SshServer à la fin de l&#8217;exécution des tests unitaires :</p>
<pre class="brush: java; title: ; notranslate">
sshd.stop();
</pre>
<h1>Code complet</h1>
<p>Vous pouvez retrouver tout ce code à peu près bien organisé, commenté avec des logs dans projet Maven :</p>
<p><img alt="" src="https://github.com/images/modules/footer/footer-logo.svg" title="Github" class="alignleft" width="100" height="44" /><br />
<a href="https://github.com/jpbriend/sftp-example" title="https://github.com/jpbriend/sftp-example" target="_blank">https://github.com/jpbriend/sftp-example</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.infin-it.fr/2012/02/10/se-connecter-a-un-serveur-sftp-en-java/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Git : comment passer à travers un proxy bloquant (push et pull)</title>
		<link>http://blog.infin-it.fr/2011/07/15/git-comment-passer-a-travers-un-proxy-bloquant-push-et-pull/</link>
		<comments>http://blog.infin-it.fr/2011/07/15/git-comment-passer-a-travers-un-proxy-bloquant-push-et-pull/#comments</comments>
		<pubDate>Fri, 15 Jul 2011 11:36:59 +0000</pubDate>
		<dc:creator><![CDATA[Jean-Philippe Briend]]></dc:creator>
				<category><![CDATA[Git]]></category>
		<category><![CDATA[github]]></category>
		<category><![CDATA[putty]]></category>
		<category><![CDATA[ssh]]></category>

		<guid isPermaLink="false">http://blog.infin-it.fr/?p=366</guid>
		<description><![CDATA[Voici la configuration que j&#8217;applique lorsque mon poste de développement se situe derrière un proxy ultra-restrictif. Je pars du principe que vous êtes dans une entreprise, donc vous avez hélas un poste sous Windows. Le principe est d&#8217;utiliser plink au lieu de la commande ssh fournie par défaut par msysgit. Plink va permettre d&#8217;utiliser une [&#8230;]]]></description>
				<content:encoded><![CDATA[<p><img alt="Github" src="https://github.com/images/modules/contact/heartocat.png" title="Github" class="alignleft" width="230" height="230" /></p>
<p>Voici la configuration que j&#8217;applique lorsque mon poste de développement se situe derrière un proxy ultra-restrictif. Je pars du principe que vous êtes dans une entreprise, donc vous avez hélas un poste sous Windows.</p>
<p>Le principe est d&#8217;utiliser <em>plink</em> au lieu de la commande <em>ssh</em> fournie par défaut par <a href="http://code.google.com/p/msysgit/" title="msysgit" target="_blank">msysgit</a>.<br />
<em>Plink</em> va permettre d&#8217;utiliser une clef stockée par <em>pageant</em> et de faire un tunnel SSH vers le repository git.</p>
<p><br/><br />
<span id="more-366"></span></p>
<h3>1ère étape : Télécharger plink, pageant et putty</h3>
<p>Allez sur le site de <a href="http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html" title="putty" target="_blank">putty</a> et téléchargez les exécutables suivants :</p>
<ul>
<li>putty.exe</li>
<li>plink.exe</li>
<li>pageant.exe</li>
<li>puttygen.exe</li>
</ul>
<h3>2ième étape : installer msysgit</h3>
<p>Téléchargez la dernière version de <em>msysgit</em> sur le <a href="http://code.google.com/p/msysgit/" title="msysgit" target="_blank">site officiel</a>.<br />
Suivez la procédure très bien décrite chez Github : <a href="http://help.github.com/win-set-up-git/" title="Setup Git for Windows" target="_blank">Setup Git for Windows</a>.<br />
Rien de particulier à signaler ici.</p>
<h3>3ième étape : changer l&#8217;agent SSH</h3>
<p>Nous allons maintenant changer l&#8217;agent SSH utilisé par msysgit : ajoutez la variable d&#8217;environnement <strong>GIT_SSH</strong> et mettez en valeur le chemin vers <strong>plink.exe</strong> (exemple : C:\Program Files (x86)\PuTTY\plink.exe).</p>
<h3>4ième étape : ppk-iser sa clé SSH</h3>
<p>Je pars du principe que vous avez une clé SSH générée. Elle se présente sous la forme d&#8217;une paire de fichiers (par défaut id_rsa et id_rsa.pub) contenant votre clé privée et la clé publique associée.<br />
A l&#8217;aide de <em>puttygen</em>, nous allons packager la clé au format .ppk (géré par pageant).</p>
<p>Lancez puttygen :<br />
<a href="http://blog.infin-it.fr/wp-content/uploads/2011/07/pageant_1.jpg"><img src="http://blog.infin-it.fr/wp-content/uploads/2011/07/pageant_1-300x288.jpg" alt="" title="pageant_1" width="300" height="288" class="aligncenter size-medium wp-image-380" /></a></p>
<p>Utilisez le menu <strong>Conversions</strong> puis <strong>Import key</strong>.<br />
Sélectionnez votre clé privée (par défaut id_rsa). Puttygen vous demande alors la passphrase pour accéder à votre clé.</p>
<p><a href="http://blog.infin-it.fr/wp-content/uploads/2011/07/pageant_2.jpg"><img src="http://blog.infin-it.fr/wp-content/uploads/2011/07/pageant_2-300x288.jpg" alt="" title="pageant_2" width="300" height="288" class="aligncenter size-medium wp-image-383" /></a></p>
<p>Cliquez sur le bouton <strong>Save private key</strong> pour sauvegarder votre clé au format ppk.</p>
<h3>5ième étape : charger sa clé dans pageant</h3>
<p>Pageant doit tourner pour que plink puisse l&#8217;utiliser.<br />
A chaque redémarrage du la machine, il faut rajouter la clé à pageant.</p>
<p>Lancer pageant : une icône apparait dans la barre des tâches.<br />
Un clic droit dessus vous permet de rajouter une clé (<strong>Add key</strong>).<br />
Sélectionnez votre clé au format ppk, entrez la passphrase et c&#8217;est tout.</p>
<h3>6ième étape : ajouter ssh.github.com à putty</h3>
<p>Maintenant, il faut configurer putty pour lui rajouter le site ssh.github.com.</p>
<p>Lancez putty et configurez le comme suit :</p>
<ul>
<li>Host name : <strong>ssh.github.com</strong></li>
<li>Port : <strong>443</strong></li>
<li>Dans l&#8217;onglet Proxy, entrez les informations relatives à votre proxy : hostname, port et éventuellement login/password.</li>
<li>Dans l&#8217;onglet <em>Connection &#8211; SSH &#8211; Auth</em>, chargez votre clé privé à l&#8217;aide du bouton <em>Browse</em></li>
<li>Revenez sur l&#8217;onglet Session et sauvegardez cette session avec un nom précis (par exemple <strong>gitproxy</strong>).</li>
</ul>
<p>La configuration dans putty suffit.<br />
Par contre, il faut se connecter une fois au serveur pour accepter la clé SSH du serveur : ouvrez une connection ssh avec putty grâce à la configuration précédemment créée et acceptez le certificat. Ceci n&#8217;est à faire qu&#8217;une seule fois.</p>
<h3>7ième étape : cloner un repo dans Git ou ajouter un repo distant</h3>
<p>La procédure est quasiment la même :</p>
<ul>
<li>Pour cloner un repository Git, récupérez l&#8217;URL du repository utilisant le protocole git (et non le http). Cette URL est au format : <em>git@github.com:username/myRepo.git</em>.</li>
<li>Exécutez la commande suivante pour faire le clone Git : <em>git clone git@<strong>gitproxy</strong>:username/myRepo.git</em>. Notez le remplacement de github.com par le nom de la configuration Putty.</li>
</ul>
<p>C&#8217;est tout : vous pouvez puller et pusher sur ce repository.<br />
N&#8217;oubliez pas que pour que ceci fonctionne, il faut que pageant tourne et ait votre clé privée chargée.</p>
<p>L&#8217;astuce est dans le fait que lors d&#8217;une commande Git, ce dernier va exécuter plink pour se connecter en SSH au repository distant. Plink va alors regarder l&#8217;adresse dans l&#8217;URL, et chercher dans putty si une configuration existe avec ce nom. Comme c&#8217;est le cas, il va utiliser la configuration putty pour se connecter.</p>
<p>Pour ajouter un repository distant, faites de même avec :<br />
<em>git remote add monRepo git@gitproxy:username/myRepo.git</em><br />
N&#8217;oubliez pas de substituer github.com par gitproxy.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.infin-it.fr/2011/07/15/git-comment-passer-a-travers-un-proxy-bloquant-push-et-pull/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Une application Play! sur Google AppEngine</title>
		<link>http://blog.infin-it.fr/2010/12/27/une-application-play-sur-google-appengine/</link>
		<comments>http://blog.infin-it.fr/2010/12/27/une-application-play-sur-google-appengine/#comments</comments>
		<pubDate>Mon, 27 Dec 2010 12:18:56 +0000</pubDate>
		<dc:creator><![CDATA[Jean-Philippe Briend]]></dc:creator>
				<category><![CDATA[Play!]]></category>
		<category><![CDATA[GAE]]></category>
		<category><![CDATA[play!]]></category>

		<guid isPermaLink="false">http://blog.infin-it.fr/?p=300</guid>
		<description><![CDATA[Dans cet article, je vais vous montrer comment créer une application Play! et comment la déployer sur Google AppEngine. Google AppEngine (GAE) propose une solution d&#8217;hébergement d&#8217;applications gratuites très pratiques pour des applications Java. La liste des fonctionnalités offertes par GAE peut-être consultée ici. Le framework Play! fournit un module extrêmement bien fait pour déployer [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Dans cet article, je vais vous montrer comment créer une application Play! et comment la déployer sur Google AppEngine.</p>
<p>Google AppEngine (GAE) propose une solution d&#8217;hébergement d&#8217;applications gratuites très pratiques pour des applications Java. La liste des fonctionnalités offertes par GAE peut-être consultée <a href="http://code.google.com/appengine/docs/whatisgoogleappengine.html">ici</a>.<br />
Le framework <a href="http://www.playframework.org/">Play!</a> fournit un <a href="http://www.playframework.org/modules/gae">module</a> extrêmement bien fait pour déployer des applications sur Gae et un autre module est disponible pour gérer le Datastore Gae : <a href="http://www.playframework.org/modules/siena">Siena</a>.<br />
<span id="more-300"></span><br />
<br/></p>
<p>
<center><img src="http://code.google.com/appengine/images/appengine-silver-120x30.gif" alt="Powered by Google App Engine" /></center>
</p>
<h1>Google AppEngine</h1>
<p>
Google fournit un SDK complet pour développer des applications destinées à être hébergées par GAE. Dans le cas d&#8217;une application Play!, ce SDK est intégré au module GAE et le SDK n&#8217;est nécessaire que pour le déploiement final.<br />
Il faut récupérer ce SDK à cette adresse : <a href="http://code.google.com/appengine/downloads.html">http://code.google.com/appengine/downloads.html</a>.<br />
La version Windows nécessite d&#8217;installer aussi Python (un lien est fourni via l&#8217;installeur du SDK).
</p>
<p>
Attaquons-nous à la partie applicative de cet article !
</p>
<p>
<center><img src="http://www.playframework.org/public/images/logo.png"/></center>
</p>
<h1>Play! Framework</h1>
<p>
Tout d&#8217;abord, il faut installer les modules GAE et Siena de Play! :<br />
<code><br />
play install gae<br />
play install siena<br />
</code><br />
Une fois ces installations terminées, créons notre future application <em>test-gae</em><br />
<code><br />
play new test-gae<br />
</code><br />
Enrichissons le <em>conf/application.conf</em> nouvellement créé avec les 2 modules précédents :<br />
<code><br />
# ---- MODULES ----<br />
module.gae=${play.path}/modules/gae-1.4<br />
module.siena=${play.path}/modules/siena-1.3<br />
</code>
</p>
<h3>Le Modèle</h3>
<p>
GAE sans stocker des données dans le Datastore, ça ne sert pas à grand chose.<br />
Nous allons donc créer un objet modèle très simple que l&#8217;on retrouve dans quasiment toutes les applications : <b>User</b> !</p>
<pre class="brush: java; title: ; notranslate">
package models;

import java.util.List;
import siena.Column;
import siena.Generator;
import siena.Id;
import siena.Max;
import siena.Model;
import siena.NotNull;
import siena.Query;

public class User extends Model {
	
    @Id(Generator.AUTO_INCREMENT)
    public Long id;

    @Column(&quot;login&quot;)
    @Max(15) @NotNull
    public String login;
	
    @Column(&quot;nickname&quot;)
    @Max(15) @NotNull
    public String nickname;
    ...
    ...
}
</pre>
<p>Il y a plusieurs choses importantes à noter :</p>
<ul>
<li>La classe User étend la classe <em>siena.Model</em> et non plus la classe <em>play.Model</em> du framework Play!.<br />
Logique : <em>play.Model</em> est destiné à JPA qui n&#8217;est pas utilisé par GAE.</li>
<li>Il faut mettre un <b>Id</b> ! L&#8217;annotation <b>@Id</b> est <u>obligatoire</u> et elle doit pointer sur une variable de type <b>Long</b> nommée <b>id</b>.</li>
<li>Les autres annotations sont optionnelles. Par défaut, la table créée prendra le nom de la classe et les colonnes prendront le nom des variables sur lesquelles elles pointent.</li>
</ul>
<p>
Il va maintenant falloir ajouter des méthodes à notre modèle afin de pouvoir récupérer des données :</p>
<pre class="brush: java; title: ; notranslate">
...
static Query&lt;User&gt; all() {
    return Model.all(User.class);
}
	
public static List&lt;User&gt; findAll() {
    return all().fetch();
}
    
public static User findById(Long id) {
    return all().filter(&quot;id&quot;, id).get();
}
    
public static User findByLogin(String login) {
    return all().filter(&quot;login&quot;, login).get();
}
</pre>
<p>Nous avons ajouté une méthode protected <em>all()</em> qui créé une <b>Query</b> qui ramènera tous les Users.<br />
A partir de cette méthode, nous allons appliquer différents filtres pour ramener les données qui nous intéressent :</p>
<ul>
<li><em>fetch()</em> pour ramener toutes les données d&#8217;une Query.</li>
<li><em>filter(&#8220;id&#8221;, id).get()</em> pour filtrer les données dont l&#8217;attribut <b>id</b> est égal à <em>id</em>.</li>
<li><em>filter(&#8220;login&#8221;, login).get()</em> pour filtrer les données dont l&#8217;attribut <b>login</b> est égal à <em>login</em>.</li>
</ul>
<p>
Nous avons maintenant un petit modèle. Attaquons-nous au contrôleur dédié à User !
</p>
<h3>Le Contrôleur</h3>
<p>
Pour faire le plus simple possible, utilisons le contrôleur créé par défaut par Play! : <b>Application</b>.</p>
<pre class="brush: java; title: ; notranslate">
package controllers;

import java.util.List;

import models.User;
import play.mvc.Controller;

public class Application extends Controller {

    public static void index() {
        List&lt;User&gt; users = User.findAll();
        render(users);
    }

    public static void add(String login, String nickname) {
        User add = new User();
        add.login = login;
        add.nickname = nickname;
        add.insert();

        index();
    }

    public static void delete(Long id) {
        notFoundIfNull(id);
        User toRemove = User.findById(id);
        toRemove.delete();

        index();
    }
}
</pre>
<p>Il s&#8217;agit d&#8217;un contrôleur tout ce qu&#8217;il y a de plus classique en Play!.<br />
Une des méthodes va ramener la liste des Users, une autre va permettre d&#8217;en ajouter un et enfin la dernière permet d&#8217;en supprimer un.
</p>
<p>
Notre contrôleur est prêt, ajoutons-lui une page html pour pouvoir jouer avec !
</p>
<h3>La Vue</h3>
<p>
Contentons-nous d&#8217;utiliser le fichier index.html du contrôleur Application :</p>
<pre class="brush: xml; title: ; notranslate">
#{extends 'main.html' /}
#{set title:'Home' /}

&lt;p&gt;
&lt;h2&gt;Liste des Users :&lt;/h2&gt;
  #{list items:users, as:'user'}
    &lt;div&gt;&lt;label&gt;[${user.id}] ${user.login} (${user.nickname})&lt;/label&gt;&lt;label&gt;#{a @Application.delete(user.id)}Delete#{/a}&lt;/label&gt;&lt;/div&gt;
  #{/list}
&lt;/p&gt;

&lt;p&gt;
#{form @Application.add()}
&lt;h2&gt;Add a User :&lt;/h2&gt;
&lt;div&gt;
  &lt;label&gt;Login :&lt;/label&gt;
  &lt;input type=&quot;text&quot; name=&quot;login&quot; /&gt;
&lt;/div&gt;

&lt;div&gt;
  &lt;label&gt;Nickname :&lt;/label&gt;
  &lt;input type=&quot;text&quot; name=&quot;nickname&quot; /&gt;
&lt;/div&gt;
&lt;div&gt;
  &lt;input type=&quot;submit&quot; value=&quot;Add&quot; /&gt;
&lt;/div&gt;
#{/form}
&lt;/p&gt;
</pre>
<p>Rien que du très classique Play! : une liste pour afficher tous les Users, un lien pour supprimer un User et enfin un formulaire pour créer un User.
</p>
<p>
Notre application est désormais prête à être déployée sur Google AppEngine !<br />
Vous pouvez la tester avec un <em>play run</em>, elle devrait tourner parfaitement.
</p>
<h1>Le déploiement sur Google AppEngine</h1>
<p>
Lorsque nous avons créé l&#8217;application avec un <em>play new test-gae</em>, le module GAE a créé un répertoire <b>war</b> à la racine de notre application.<br />
Celui-ci contient un fichier généré automatiquement : <b>web.xml</b>.<br />
Il va être important de le modifier pour pouvoir déployer correctement sur GAE.</p>
<pre class="brush: xml; title: ; notranslate">
&lt;appengine-web-app xmlns=&quot;http://appengine.google.com/ns/1.0&quot;&gt;
  &lt;application&gt;&lt;!-- ID GAE de votre application --&gt;&lt;/application&gt;
  &lt;version&gt;1&lt;/version&gt;
&lt;/appengine-web-app&gt;
</pre>
<p>La balise <b>application</b> doit contenir l&#8217;ID de votre application Google AppEengine.<br />
Pour le déterminer, il faut créer une application dans Google AppEngine.
</p>
<h3>Créer une application dans Google AppEngine</h3>
<p>
Rendez-vous sur <a href="https://appengine.google.com/">https://appengine.google.com/</a>.<br />
Vous devez vous identifier avec votre compte Gmail.<br />
Lors de la création de votre première application, il vous demandera sûrement un numéro de téléphone portable pour vous envoyer un code.<br />
Une fois cette étape passée, vous devriez pouvoir créer une application Google AppEngine :<br />
<img src="http://blog.infin-it.fr/wp-content/uploads/2010/12/Gae_Create.jpg" width="600" height="320"/><br />
C&#8217;est le champ <em>Application Identifier</em> qui contient l&#8217;id de votre application à mettre dans votre fichier <em>web.xml</em>.
</p>
<p>
Hop, votre application a dûe être déclarée dans Google AppEngine !
</p>
<h3>Déployer l&#8217;application sur Google AppEngine</h3>
<p>
Ma petite soeur peut le faire : en se plaçant dans le répertoire de notre application, il suffit de lancer :<br />
<code><br />
play gae:deploy --gae={path_to_gae_sdk}<br />
</code><br />
<em>path_to_gae_sdk</em> indique votre installation du SDK Google AppEngine.
</p>
</p>
<p>Vous devriez voir Play! précompiler les classes, assembler un war puis tenter d&#8217;uploader votre application.<br />
Il vous demanderas sûrement votre login et mot de passe Gmail pour vous identifier sur votre compte.<br />
Une fois l&#8217;upload terminé, vous pouvez administrer votre application grâce à la console AppEngine :<br />
<a href="https://appengine.google.com">https://appengine.google.com</a></p>
<p>Votre application est disponible à l&#8217;url indiquée par la console d&#8217;administration :<br />
<center><img src="http://blog.infin-it.fr/wp-content/uploads/2010/12/Gae_deployed.jpg" style="border: 1px solid black;"/></center>
</p>
<p>
Voici l&#8217;archive du projet, prête à l&#8217;emploi : <a href="http://blog.infin-it.fr/wp-content/uploads/2010/12/test-gae.zip">Zip</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.infin-it.fr/2010/12/27/une-application-play-sur-google-appengine/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Play! Framework : enrichir votre application avec un éditeur riche Textile</title>
		<link>http://blog.infin-it.fr/2010/12/16/play-framework-enrichir-votre-application-avec-un-editeur-riche-textile/</link>
		<comments>http://blog.infin-it.fr/2010/12/16/play-framework-enrichir-votre-application-avec-un-editeur-riche-textile/#comments</comments>
		<pubDate>Thu, 16 Dec 2010 17:34:37 +0000</pubDate>
		<dc:creator><![CDATA[Jean-Philippe Briend]]></dc:creator>
				<category><![CDATA[Play!]]></category>
		<category><![CDATA[markItUp]]></category>
		<category><![CDATA[play!]]></category>

		<guid isPermaLink="false">http://blog.infin-it.fr/?p=262</guid>
		<description><![CDATA[L'objectif est d'intégrer dans une page un éditeur de texte riche au format Textile. Cette syntaxe est très simple à appréhender et la génération de code HTML à partir de code Textile est native dans Play! grâce à la librairie Wikitext.]]></description>
				<content:encoded><![CDATA[<p>Voici un billet un peu plus pratique utilisant le framework <a href="http://www.playframework.org/">Play!</a>.<br />
Contrairement à mon <a href="http://blog.infin-it.fr/2010/12/15/play-framework-integration-continue-retour-dexperience/">billet précédent</a>, celui-ci s&#8217;adresse avant tout aux développeurs.</p>
<p>L&#8217;objectif est d&#8217;intégrer dans une page un éditeur de texte riche au format <a href="http://fr.wikipedia.org/wiki/Textile_(langage)">Textile</a>. Cette syntaxe est très simple à appréhender et la génération de code HTML à partir de code Textile est native dans Play! grâce à la librairie <a href="http://wiki.eclipse.org/Mylyn/Incubator/WikiText">Wikitext</a>.</p>
<p>En ce qui concerne l&#8217;éditeur en tant que tel, nous allons utiliser l&#8217;excellent <a href="http://markitup.jaysalvat.com">MarkItUp</a>. Il est basé sur <a href="http://jquery.com/">jQuery</a>, lui même nativement embarqué par Play!. MarkItUp propose un éditeur modulaire, permettant de gérer plusieurs syntaxes. L&#8217;ajout de syntaxes se fait par des <em>sets</em>.</p>
<p><img src="http://blog.infin-it.fr/wp-content/uploads/2010/12/markItUp.jpg" /><br />
<span id="more-262"></span></p>
<h1>MarkItUp</h1>
<p>Commençons par télécharger <em>MarkItUp! pack</em> sur la page des <a href="http://markitup.jaysalvat.com/downloads/">téléchargements</a>.<br />
Il faut aussi prendre le <em>Basic Textile Set</em>.<br />
L&#8217;archive MarkItUp contient un répertoire <em><strong>markitup</strong></em> : c&#8217;est celui-ci qu&#8217;il faut décompresser dans le répertoire <em><strong>public</strong></em> de votre application Play!.<br />
Il faut ensuite décompresser l&#8217;archive contenant le <em>Basic Textile Set</em> dans le répertoire <em><strong>public/markitup/sets</strong></em> : un nouveau répertoire <em><strong>textile</strong></em> a dû apparaître.</p>
<p>L&#8217;installation des fichiers de MarkItUp est désormais terminée. Nous reviendrons plus tard pour la configuration et la customisation de l&#8217;éditeur.</p>
<h1>Générateur Wikitext</h1>
<p>Nous allons avoir besoin de 2 méthodes :</p>
<ul>
<li>une 1ère méthode pour générer le code destiné à l&#8217;iframe Preview. Qui dit iframe dit qu&#8217;il va falloir rajouter les feuilles css au code HTML généré.</li>
<li>une 2ième méthode destinée à générer le code qui sera faire le rendu du code Textile saisi par l&#8217;utilisateur. Cette fois-ci, il ne faut pas que les css soient inclues dans le code html généré.</li>
</ul>
<p>J&#8217;ai décidé de créer ces 2 méthodes dans un Controler :</p>
<pre class="brush: java; title: ; notranslate">
package controllers;

import java.io.StringWriter;

import jj.play.org.eclipse.mylyn.wikitext.core.parser.MarkupParser;
import jj.play.org.eclipse.mylyn.wikitext.core.parser.builder.HtmlDocumentBuilder;
import jj.play.org.eclipse.mylyn.wikitext.core.parser.builder.HtmlDocumentBuilder.Stylesheet;
import jj.play.org.eclipse.mylyn.wikitext.textile.core.TextileLanguage;
import play.mvc.Controller;

public class Wikitext extends Controller {

    // Controller classique Play! qui sera appelé par l'iframe Preview de MarkItUp.
    public static void renderPreview(String wiki) {
        StringWriter writer = new StringWriter();
        HtmlDocumentBuilder builder = new HtmlDocumentBuilder(writer);

        // Ajout de mes 2 css.
        Stylesheet css = new Stylesheet(&quot;/public/stylesheets/main.css&quot;);
        builder.addCssStylesheet(css);
        css = new Stylesheet(&quot;/public/stylesheets/wiki.css&quot;);
        builder.addCssStylesheet(css);

        // Création du parser Textile
        MarkupParser parser = new MarkupParser(new TextileLanguage());
        parser.setBuilder(builder);
        parser.parse(wiki);

        String htmlContent = writer.toString();
        renderText(htmlContent);
    }

    // Méthode qui sera appelée par les templates Groovy de Play!.
    public static String render(String wiki) {
        StringWriter writer = new StringWriter();
        HtmlDocumentBuilder builder = new HtmlDocumentBuilder(writer);
        // Empêche la génération des balises html et body.
        builder.setEmitAsDocument(false);

        // Création du parser Textile
        MarkupParser parser = new MarkupParser(new TextileLanguage());
        parser.setBuilder(builder);
        parser.parse(wiki);

        return writer.toString();
    }
}
</pre>
<p>Ces 2 méthodes n&#8217;ont rien de spécial : elles utilisent Wikitext qui parse le code Textile de l&#8217;utilisateur et en fait un rendu HTML.<br />
Notez dans l&#8217;une l&#8217;ajout de mes 2 css alors que l&#8217;autre méthode ne génère pas les tags <em>html</em> et <em>body</em>.</p>
<p>Afin de rendre ce controller un peu plus sexy, ajoutons lui une route pour le rendu de Preview :</p>
<pre class="brush: plain; title: ; notranslate">
 
*       /wikitext/renderPreview                 Wikitext.renderPreview
 
</pre>
<h1>Installation de markItUp dans nos templates</h1>
<p>Tout d&#8217;abord, il faut ajouter dans la page que vous voulez enrichier de notre éditeur riche le code suivant qui chargera markItUp :</p>
<pre class="brush: xml; title: ; notranslate">
&lt;!--  Loading Markitup --&gt;
&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;@{'/public/markitup/skins/markitup/style.css'}&quot; /&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;@{'/public/markitup/jquery.markitup.js'}&quot;&gt;&lt;/script&gt;

&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;@{'/public/markitup/sets/textile/style.css'}&quot; /&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;@{'/public/markitup/sets/textile/set.js'}&quot;&gt;&lt;/script&gt;

&lt;script language=&quot;javascript&quot;&gt;
$(document).ready(function()    {
    $('#wiki').markItUp(mySettings);
});
&lt;/script&gt;
&lt;!-- End markitup --&gt;
</pre>
<p>Attention à modifier le code ci-dessus pour que l&#8217;identifiant &#8216;#wiki&#8217; pointe bien vers l&#8217;id du <em>textarea</em> que vous voulez enrichir avec markItUp.<br />
De plus, notez la variable <em>mySettings</em>. Celle-ci contient la configuration du plugin markItUp sous format JSON.</p>
<p>Voici un exemple de textarea qui va être enrichi par le plugin markItUp :</p>
<pre class="brush: xml; title: ; notranslate">
&lt;textarea id=&quot;wiki&quot; name=&quot;description&quot; cols=&quot;70&quot; rows=&quot;20&quot;&gt;
    Bla Bla ...
&lt;/textarea&gt;
</pre>
<h1>Configuration et customisation de markItUp</h1>
<p>Il va falloir maintenant configurer et customiser markItUp.</p>
<p>Pour cela, il va falloir commencer par éditer le fichier <em><strong>public/markitup/sets/textile/set.js</strong></em> :</p>
<pre class="brush: css; title: ; notranslate">
mySettings = {
	previewParserPath:	'/wikitext/renderPreview', // path to your Wiki parser
	previewParserVar:	'wiki',
	onShiftEnter:		{keepDefault:false, replaceWith:'\n\n'},
	markupSet: [
		{name:'Heading 1', key:'1', openWith:'h1(!(([![Class]!]))!). ', placeHolder:'Your title here...' },
		{name:'Heading 2', key:'2', openWith:'h2(!(([![Class]!]))!). ', placeHolder:'Your title here...' },
		{name:'Heading 3', key:'3', openWith:'h3(!(([![Class]!]))!). ', placeHolder:'Your title here...' },
		{name:'Heading 4', key:'4', openWith:'h4(!(([![Class]!]))!). ', placeHolder:'Your title here...' },
		{name:'Heading 5', key:'5', openWith:'h5(!(([![Class]!]))!). ', placeHolder:'Your title here...' },
		{name:'Heading 6', key:'6', openWith:'h6(!(([![Class]!]))!). ', placeHolder:'Your title here...' },
		{name:'Paragraph', key:'P', openWith:'p(!(([![Class]!]))!). '},
		{separator:'---------------' },
		{name:'Bold', key:'B', closeWith:'*', openWith:'*'},
		{name:'Italic', key:'I', closeWith:'_', openWith:'_'},
		{name:'Stroke through', key:'S', closeWith:'-', openWith:'-'},
		{separator:'---------------' },
		{name:'Bulleted list', openWith:'(!(* |!|*)!)'},
		{name:'Numeric list', openWith:'(!(# |!|#)!)'}, 
		{separator:'---------------' },
		{name:'Picture', replaceWith:'![![Source:!:http://]!]([![Alternative text]!])!'}, 
		{name:'Link', openWith:'&quot;', closeWith:'([![Title]!])&quot;:[![Link:!:http://]!]', placeHolder:'Your text to link here...' },
		{separator:'---------------' },
		{name:'Quotes', openWith:'bq(!(([![Class]!]))!). '},
		{name:'Code', openWith:'@', closeWith:'@'},
		{separator:'---------------' },
		{name:'Preview', call:'preview', className:'preview'}
	]
}
</pre>
<p>J&#8217;ai fais les modifications suivantes :</p>
<ul>
<li>Remplissage de la variable <strong>previewParserPath</strong> : on pointe vers le controller que nous avons écrit plus tôt.</li>
<li>Ajout de la variable <strong>previewParserVar</strong> pour donner le nom du paramètre HTTP contenant le code à envoyer au controller.</li>
</ul>
<p>Le reste du fichier sert à configurer l&#8217;apparence et les boutons de markItUp. Je vous laisse le soin de fouiller la documentation de ce plugin si vous le souhaitez.</p>
<p>Il ne reste qu&#8217;à terminer par un peu de customisation via une CSS.<br />
J&#8217;ai modifié le fichier <em><strong>public/markitup/sets/textile/style.css</strong></em> et j&#8217;ai rajouté les lignes suivantes :</p>
<pre class="brush: css; title: ; notranslate">
.markItUp  {
    width:500px;
}

.markItUpEditor {
    width:443px;
    height:220px;
}
</pre>
<p>Ces surcharges me servent uniquement à redimensionner markItUp.</p>
<p>Et voilà !<br />
En une petite dizaine de minutes, nous avons réussi à transformer un simple Textarea en un éditeur riche supportant Textile avec un rendu aux petits oignons. Soignez votre CSS de rendu et vous êtes le roi du pétrole !</p>
<p><strong>Bonus </strong>: Voici un projet Play! contenant le code de cet article. Lancez-le avec un <em>play run</em> et ça marche !<br />
<a href="http://blog.infin-it.fr/wp-content/uploads/2010/12/sample-markitup.zip">Télécharger le code</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.infin-it.fr/2010/12/16/play-framework-enrichir-votre-application-avec-un-editeur-riche-textile/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Play! Framework / Intégration Continue : retour d&#8217;expérience</title>
		<link>http://blog.infin-it.fr/2010/12/15/play-framework-integration-continue-retour-dexperience/</link>
		<comments>http://blog.infin-it.fr/2010/12/15/play-framework-integration-continue-retour-dexperience/#comments</comments>
		<pubDate>Wed, 15 Dec 2010 08:42:10 +0000</pubDate>
		<dc:creator><![CDATA[Jean-Philippe Briend]]></dc:creator>
				<category><![CDATA[Play!]]></category>
		<category><![CDATA["intégration continue"]]></category>
		<category><![CDATA[play!]]></category>

		<guid isPermaLink="false">http://blog.infin-it.fr/?p=224</guid>
		<description><![CDATA[Depuis le 2 novembre, la version 1.1 du framework Play! est disponible. Je ne vous ferai pas une présentation de ce framework, il en existe plusieurs dont celle du Touilleur Express (Play! Framework). Je vais plutôt vous faire un retour d&#8217;expérience de la mise en place des outils nécessaires pour intégrer des applications Play! à [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Depuis le 2 novembre, la version 1.1 du framework <a href="http://www.playframework.org">Play!</a> est disponible.<br />
Je ne vous ferai pas une présentation de ce framework, il en existe plusieurs dont celle du Touilleur Express (<a href="http://www.touilleur-express.fr/2010/02/12/version-play-de-lapplication-zencontact-de-zenika/">Play! Framework</a>).</p>
<p>Je vais plutôt vous faire un retour d&#8217;expérience de la mise en place des outils nécessaires pour intégrer des applications Play! à notre usine d&#8217;Intégration Continue.<br />
<span id="more-224"></span><br />
Commençons par la description de notre environnement, très classique :</p>
<ul>
<li>tous les projets Java sont mavenisés (<a href="http://maven.apache.org/">Maven 2</a>).</li>
<li>tous les projets définissent des tests unitaires (<a href="http://www.junit.org/">JUnit</a>).</li>
<li>certains projets ont des tests <a href="http://seleniumhq.org/">Selenium</a>.</li>
<li>tous les projets ont des builds lancés automatiquement par <a href="http://www.atlassian.com/software/bamboo/">Bamboo</a>.</li>
<li>tous les projets sont analysés par <a href="http://www.sonarsource.org/">Sonar</a> chaque nuit</li>
</ul>
<p>La tâche est de faire rentrer les futures applications écrites avec Play! dans cette chaîne d&#8217;Intégration Continue.</p>
<h2>Mavenisation d&#8217;une application Play!</h2>
<p>Il s&#8217;agit de l&#8217;étape qui fut la plus compliquée et surtout la plus longue. Le cahier des charges est le suivant :</p>
<ul>
<li>Gestion des dépendances applicatives (ie: remplir le répertoire /lib avec les dependencies Maven du projet).</li>
<li>Gestion des librairies inclues dans le framework Play! (afin que la phase <em>compile</em> se passe correctement).</li>
<li>Maven doit pouvoir faire exécuter les tests unitaires et en récupérer un rapport Surefire.</li>
<li>Maven doit pouvoir exécuter Cobertura sur l&#8217;application et en extraire un rapport (à destination de Sonar).</li>
<li>Une analyse Sonar doit être effectuée sur l&#8217;application.</li>
</ul>
<h3>Gestion des dépendances applicatives</h3>
<p>Avec un peu de configuration Maven, (<a href="http://maven.apache.org/plugins/maven-dependency-plugin/">plugin dependency</a>), il est assez facile de faire exporter les librairies applicatives dans le répertoires <em>lib</em> de l&#8217;application, ainsi que de les supprimer lors d&#8217;un <em>mvn clean</em>.</p>
<pre class="brush: xml; title: ; notranslate">
  &lt;plugin&gt;
        &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
        &lt;artifactId&gt;maven-dependency-plugin&lt;/artifactId&gt;
        &lt;version&gt;2.1&lt;/version&gt;
        &lt;executions&gt;
          &lt;execution&gt;
            &lt;id&gt;default-cli&lt;/id&gt;
            &lt;configuration&gt;
              &lt;includeClassifiers&gt;,sources&lt;/includeClassifiers&gt;
              &lt;outputDirectory&gt;lib/&lt;/outputDirectory&gt;
              &lt;excludeScope&gt;provided&lt;/excludeScope&gt;
              &lt;!-- To download sources jars without failing --&gt;
              &lt;failOnMissingClassifierArtifact&gt;false&lt;/failOnMissingClassifierArtifact&gt;
              &lt;excludeArtifactIds&gt;play-runtime,play&lt;/excludeArtifactIds&gt;
            &lt;/configuration&gt;
         ...
</pre>
<h3>Gestion des dépendances du framework Play!</h3>
<p>Là, le boulot est un peu plus long car j&#8217;ai dû référencer toutes les librairies du framework. Cependant les versions sont très standard (mis à part un patch sur Hibernate), donc le boulot se fait bien.<br />
Petit écueil : certaines librairies n&#8217;existent pas dans les repository standards. Il y en a donc certaines qui doivent être uploadées dans votre Nexus d&#8217;entreprise.</p>
<p>Ces 2 étapes doivent vous permettre de compiler un projet Play! sous Maven sans encombre.</p>
<p>Maintenant que la compilation fonctionne, préparons l&#8217;exécution des tests unitaires via le runtime de Play!</p>
<h3>Le Runtime de Play! pour les Tests unitaires</h3>
<p>Je sais que la pratique suivante fera bondir certains, mais le runtime de Play! est tout simplement beaucoup trop puissant pour que l&#8217;on puisse s&#8217;en passer !<br />
Nous ne voulions pas devoir gérer l&#8217;installation du runtime sur les différents environnements où les agents Bamboo sont déployés. Il faut donc le packager sous forme de ressources avec ses modules intégrés dans le repository Maven. Une tâche Ant se chargera de le dézipper afin que la commande <em>play</em> soit accessible.</p>
<pre class="brush: xml; title: ; notranslate">
  &lt;dependency&gt;
    &lt;groupId&gt;org.play&lt;/groupId&gt;
    &lt;artifactId&gt;play-runtime&lt;/artifactId&gt;
    &lt;version&gt;1.1&lt;/version&gt;
    &lt;type&gt;zip&lt;/type&gt;
  &lt;/dependency&gt;
</pre>
<h2>Les tests unitaires</h2>
<p>Les tests unitaires de Play! framework sont des tests JUnit mais lancés par le runtime Play!.</p>
<p>La commande <em>auto-test</em> permet de lancer les tests unitaires et les tests Selenium automatiquement. Un reporting sous forme de fichier html est généré. J&#8217;ai donc dû enrichir le framework pour générer un rapport au format <a href="http://maven.apache.org/plugins/maven-surefire-plugin/">Surefire</a>. Ce rapport contient le nombre de tests unitaires joués, le nombre d&#8217;erreurs, d&#8217;echecs, le temps passé ainsi qu&#8217;un détail des erreurs.<br />
Un script ant permet de faire lancer par Maven le framework Play! en mode <em>auto-test</em>.</p>
<p>Voici une exécution Maven du plugin mavent-antrun-plugin :</p>
<pre class="brush: xml; title: ; notranslate">
&lt;execution&gt;
  &lt;id&gt;UnitTests&lt;/id&gt;
  &lt;phase&gt;test&lt;/phase&gt;
  &lt;configuration&gt;
    &lt;target&gt;
      &lt;property name=&quot;maven.project.artifactId&quot; value=&quot;${project.artifactId}&quot; /&gt;
      &lt;property name=&quot;maven.project.version&quot; value=&quot;${project.version}&quot; /&gt;
      &lt;property name=&quot;maven.project.play-runtime&quot; value=&quot;play-runtime-${play.version}&quot; /&gt;

      &lt;property name=&quot;play.runtime.path&quot; value=&quot;${basedir}/target/dependency/${maven.project.play-runtime}&quot; /&gt;
      &lt;property name=&quot;play.runtime.file&quot; value=&quot;${basedir}/target/dependency/${maven.project.play-runtime}.zip&quot; /&gt;
      &lt;property name=&quot;play.runtime.unzip.path&quot; value=&quot;${basedir}/target/dependency&quot; /&gt;

      &lt;!-- Check zipped Play! runtime is present. Build fails if not present --&gt;
      &lt;available file=&quot;${play.runtime.file}&quot; property=&quot;play.runtime.present&quot; /&gt;
      &lt;echo message=&quot;Is Play! runtime present : ${play.runtime.present}&quot; /&gt;

      &lt;fail message=&quot;Error : Play! runtime could not be found at : ${play.runtime.file}&quot;&gt;
        &lt;condition&gt;
          &lt;not&gt;
            &lt;isset property=&quot;play.runtime.present&quot; /&gt;
          &lt;/not&gt;
        &lt;/condition&gt;
      &lt;/fail&gt;

      &lt;!-- Delete existing Play! runtime --&gt;
      &lt;echo message=&quot;Deleting any existing unzipped Play! runtime ...&quot; /&gt;
      &lt;delete dir=&quot;play.runtime.unzip.path&quot; failonerror=&quot;false&quot; verbose=&quot;true&quot; /&gt;

      &lt;!-- Unzip Play! runtime --&gt;
      &lt;echo message=&quot;Unzipping Play! runtime ...&quot; /&gt;
      &lt;unzip src=&quot;${play.runtime.file}&quot; dest=&quot;${play.runtime.unzip.path}&quot; /&gt;
      &lt;echo message=&quot;Play! runtime unzipped successfully.&quot; /&gt;
      &lt;chmod dir=&quot;${play.runtime.path}&quot; perm=&quot;ugo+x&quot; includes=&quot;play&quot; /&gt;

      &lt;!-- launch play mvn:up to retrieve libs in /lib folder --&gt;
      &lt;condition property=&quot;playExtension&quot; value=&quot;.bat&quot;&gt;
        &lt;and&gt;
          &lt;os family=&quot;windows&quot; /&gt;
        &lt;/and&gt;
      &lt;/condition&gt;
      &lt;condition property=&quot;playExtension&quot; value=&quot;&quot;&gt;
        &lt;and&gt;
          &lt;os family=&quot;unix&quot; /&gt;
        &lt;/and&gt;
      &lt;/condition&gt;
      &lt;exec executable=&quot;${play.runtime.unzip.path}/${maven.project.play-runtime}/play${playExtension}&quot;&gt;
        &lt;arg value=&quot;mvn:up&quot; /&gt;
      &lt;/exec&gt;

      &lt;!-- Launch Play war command --&gt;
      &lt;condition property=&quot;playExtension&quot; value=&quot;.bat&quot;&gt;
        &lt;and&gt;
          &lt;os family=&quot;windows&quot; /&gt;
        &lt;/and&gt;
      &lt;/condition&gt;
      &lt;condition property=&quot;playExtension&quot; value=&quot;&quot;&gt;
        &lt;and&gt;
          &lt;os family=&quot;unix&quot; /&gt;
        &lt;/and&gt;
      &lt;/condition&gt;
      &lt;exec executable=&quot;${play.runtime.unzip.path}/${maven.project.play-runtime}/play${playExtension}&quot;&gt;
        &lt;arg value=&quot;auto-test&quot; /&gt;
      &lt;/exec&gt;
    &lt;/target&gt;
  &lt;/configuration&gt;
  &lt;goals&gt;
    &lt;goal&gt;run&lt;/goal&gt;
  &lt;/goals&gt;
&lt;/execution&gt;
</pre>
<p>L&#8217;étape des Tests Unitaires est désormais ok !</p>
<h2>L&#8217;analyse Cobertura</h2>
<p>Que serait une analyse Sonar sans le plugin Cobertura !</p>
<p>Heureusement, il existe un module Cobertura pour la framework Play! Il est très bien intégré puisqu&#8217;il suffit de le configurer dans votre application.conf et il l&#8217;analyse Cobertura sera effectuée durant la phase des tests unitaires. Un rapport est généré. Le seul travail à faire est de référencer dans Sonar l&#8217;emplacement de ce rapport pour que ce dernier puisse l&#8217;exploiter.</p>
<p>Je vous conseille la documentation de ce très bon module Play! : <a href="http://www.playframework.org/modules/cobertura-2.0/home">Documentation module Cobertura</a>.</p>
<h2>Le packaging</h2>
<p>Un gros morceau là aussi.</p>
<p>Le packaging d&#8217;une application Play! doit être fait sous forme de war pour pouvoir être uploadé dans un repository Maven.<br />
L&#8217;idée retenue est que l&#8217;on va laisser Maven exécuter sa phase <em>package</em> qui buildera un war non fonctionnel, puis une tâche Ant branchée sur cette même phase va générer grâce à la commande <em>play war</em> un fichier war Play! fonctionnel. Le principal soucis rencontré fût l&#8217;exclusion du répertoire <em>target</em> du packaging fait par Play! (notre target contient notamment le runtime Play!). Un développement soumis sur Github nous a permis de rajouter un paramètre <em>&#8211;exclude</em> à la ligne de commande <em>play war</em> et d&#8217;exclure les répertoires que nous ne voulions pas builder.</p>
<p>Voici l&#8217;exécution Maven du plugin Antrun :</p>
<pre class="brush: xml; title: ; notranslate">
&lt;execution&gt;
  &lt;id&gt;Packaging&lt;/id&gt;
  &lt;phase&gt;package&lt;/phase&gt;
  &lt;configuration&gt;
    &lt;target&gt;
      &lt;property name=&quot;maven.project.artifactId&quot; value=&quot;${project.artifactId}&quot; /&gt;
      &lt;property name=&quot;maven.project.version&quot; value=&quot;${project.version}&quot; /&gt;
      &lt;property name=&quot;maven.project.play-runtime&quot; value=&quot;play-runtime-${play.version}&quot; /&gt;

      &lt;property name=&quot;play.runtime.path&quot; value=&quot;${basedir}/target/dependency/${maven.project.play-runtime}&quot; /&gt;
      &lt;property name=&quot;play.runtime.file&quot; value=&quot;${basedir}/target/dependency/${maven.project.play-runtime}.zip&quot; /&gt;
      &lt;property name=&quot;play.runtime.unzip.path&quot; value=&quot;${basedir}/target/dependency&quot; /&gt;

      &lt;!-- Check zipped Play! runtime is present. Build fails if not present --&gt;
      &lt;available file=&quot;${play.runtime.file}&quot; property=&quot;play.runtime.present&quot; /&gt;
      &lt;echo message=&quot;Is Play! runtime present : ${play.runtime.present}&quot; /&gt;

      &lt;fail message=&quot;Error : Play! runtime could not be found at : ${play.runtime.file}&quot;&gt;
        &lt;condition&gt;
          &lt;not&gt;
            &lt;isset property=&quot;play.runtime.present&quot; /&gt;
          &lt;/not&gt;
        &lt;/condition&gt;
      &lt;/fail&gt;

      &lt;!-- Delete existing Play! runtime --&gt;
      &lt;echo message=&quot;Deleting any existing unzipped Play! runtime ...&quot; /&gt;
      &lt;delete dir=&quot;play.runtime.unzip.path&quot; failonerror=&quot;false&quot; verbose=&quot;true&quot; /&gt;

      &lt;!-- Unzip Play! runtime --&gt;
      &lt;echo message=&quot;Unzipping Play! runtime ...&quot; /&gt;
      &lt;unzip src=&quot;${play.runtime.file}&quot; dest=&quot;${play.runtime.unzip.path}&quot; /&gt;
      &lt;echo message=&quot;Play! runtime unzipped successfully.&quot; /&gt;
      &lt;chmod dir=&quot;${play.runtime.path}&quot; perm=&quot;ugo+x&quot; includes=&quot;play&quot; /&gt;

      &lt;!-- launch play mvn:up to retrieve libs in /lib folder --&gt;
      &lt;condition property=&quot;playExtension&quot; value=&quot;.bat&quot;&gt;
        &lt;and&gt;
          &lt;os family=&quot;windows&quot; /&gt;
        &lt;/and&gt;
      &lt;/condition&gt;
      &lt;condition property=&quot;playExtension&quot; value=&quot;&quot;&gt;
        &lt;and&gt;
          &lt;os family=&quot;unix&quot; /&gt;
        &lt;/and&gt;
      &lt;/condition&gt;
      &lt;exec executable=&quot;${play.runtime.unzip.path}/${maven.project.play-runtime}/play${playExtension}&quot;&gt;
        &lt;arg value=&quot;mvn:up&quot; /&gt;
      &lt;/exec&gt;

      &lt;!-- Launch Play war command --&gt;
      &lt;condition property=&quot;playExtension&quot; value=&quot;.bat&quot;&gt;
        &lt;and&gt;
          &lt;os family=&quot;windows&quot; /&gt;
        &lt;/and&gt;
      &lt;/condition&gt;
      &lt;condition property=&quot;playExtension&quot; value=&quot;&quot;&gt;
        &lt;and&gt;
          &lt;os family=&quot;unix&quot; /&gt;
        &lt;/and&gt;
      &lt;/condition&gt;
      &lt;exec executable=&quot;${play.runtime.unzip.path}/${maven.project.play-runtime}/play${playExtension}&quot;&gt;
        &lt;arg value=&quot;war&quot; /&gt;
        &lt;arg value=&quot;${basedir}&quot; /&gt;
        &lt;arg value=&quot;-o&quot; /&gt;
        &lt;arg value=&quot;${basedir}/target/${maven.project.artifactId}-${maven.project.version}&quot; /&gt;
        &lt;arg value=&quot;--zip&quot; /&gt;
        &lt;arg value=&quot;--exclude&quot; /&gt;
        &lt;arg value=&quot;target&quot; /&gt;
      &lt;/exec&gt;
    &lt;/target&gt;
  &lt;/configuration&gt;
  &lt;goals&gt;
    &lt;goal&gt;run&lt;/goal&gt;
  &lt;/goals&gt;
&lt;/execution&gt;
</pre>
<p>Nous avons donc les tests unitaires, l&#8217;analyse Cobertura, le packaging en War et le déploiement dans un repo Maven qui fonctionnent. Il ne nous reste plus qu&#8217;à attaquer l&#8217;analyse Sonar.</p>
<h2>L&#8217;analyse Sonar</h2>
<p>Avec un peu de configuration (emplacement des sources, des fichiers Surefire, Cobertura, etc&#8230;), la configuration du plugin Sonar s&#8217;est passée sans encombres.</p>
<p>Nous avons donc réussi à intégrer les applications Play! à notre usine d&#8217;Intégration Continue.<br />
Les projets ont donc uniquement besoin d&#8217;un pom avec les bonnes dépendances pour pouvoir commencer leurs développements et qu&#8217;ils soient compatibles Usine de Développement.</p>
<p>Conclusion : malgré quelques difficultés, l&#8217;intégration du framework Play! s&#8217;est faite sans gros soucis. Nous avons ainsi pu rentrer dans le code du framework, autant du côté Python que du côté Java. Quelques Pull Request chez Github et nous sommes pleinement fonctionnels !</p>
<p>Merci à Play! framework et à toute son équipe !</p>
<p>Update 16/12/2010 :<br />
Suite aux commentaires, voici le contenu du pom parent pour la version 1.1 de Play! :</p>
<pre class="brush: xml; collapse: true; light: false; title: ; toolbar: true; notranslate">
&lt;project xmlns=&quot;http://maven.apache.org/POM/4.0.0&quot; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
  xsi:schemaLocation=&quot;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd&quot;&gt;
  &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;
  &lt;groupId&gt;org.play&lt;/groupId&gt;
  &lt;artifactId&gt;play-parent&lt;/artifactId&gt;
  &lt;version&gt;1.1&lt;/version&gt;
  &lt;packaging&gt;pom&lt;/packaging&gt;
  &lt;name&gt;Play's parent POM&lt;/name&gt;
  
  &lt;repositories&gt;
    &lt;!-- Repository containing Play! jars. If you have your own repo (ex: Nexus), upload missing libs in third-parties --&gt;
    &lt;repository&gt;
      &lt;id&gt;infin-it&lt;/id&gt;
      &lt;url&gt;http://nexus.infin-it.fr/content/groups/public&lt;/url&gt;
      &lt;releases&gt;
        &lt;enabled&gt;true&lt;/enabled&gt;
      &lt;/releases&gt;
      &lt;snapshots&gt;
        &lt;enabled&gt;false&lt;/enabled&gt;
      &lt;/snapshots&gt;
    &lt;/repository&gt;
  &lt;/repositories&gt;  
    
  &lt;properties&gt;
    &lt;play.version&gt;1.1&lt;/play.version&gt;
  &lt;/properties&gt;

  &lt;dependencies&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;javax.activation&lt;/groupId&gt;
      &lt;artifactId&gt;activation&lt;/artifactId&gt;
      &lt;version&gt;1.1.1&lt;/version&gt;
      &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;antlr&lt;/groupId&gt;
      &lt;artifactId&gt;antlr&lt;/artifactId&gt;
      &lt;version&gt;2.7.6&lt;/version&gt;
      &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;com.ning&lt;/groupId&gt;
      &lt;artifactId&gt;async-http-client&lt;/artifactId&gt;
      &lt;version&gt;1.2.0&lt;/version&gt;
      &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;org.bouncycastle&lt;/groupId&gt;
      &lt;artifactId&gt;bcprov-jdk15&lt;/artifactId&gt;
      &lt;version&gt;1.45&lt;/version&gt;
      &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;c3p0&lt;/groupId&gt;
      &lt;artifactId&gt;c3p0&lt;/artifactId&gt;
      &lt;version&gt;0.9.1.2&lt;/version&gt;
      &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;cglib&lt;/groupId&gt;
      &lt;artifactId&gt;cglib-nodep&lt;/artifactId&gt;
      &lt;version&gt;2.2&lt;/version&gt;
      &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;commons-beanutils&lt;/groupId&gt;
      &lt;artifactId&gt;commons-beanutils&lt;/artifactId&gt;
      &lt;version&gt;1.8.3&lt;/version&gt;
      &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;commons-codec&lt;/groupId&gt;
      &lt;artifactId&gt;commons-codec&lt;/artifactId&gt;
      &lt;version&gt;1.4&lt;/version&gt;
      &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;commons-collections&lt;/groupId&gt;
      &lt;artifactId&gt;commons-collections&lt;/artifactId&gt;
      &lt;version&gt;3.1&lt;/version&gt;
      &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;org.apache.commons&lt;/groupId&gt;
      &lt;artifactId&gt;commons-email&lt;/artifactId&gt;
      &lt;version&gt;1.2&lt;/version&gt;
      &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;commons-fileupload&lt;/groupId&gt;
      &lt;artifactId&gt;commons-fileupload&lt;/artifactId&gt;
      &lt;version&gt;1.2&lt;/version&gt;
      &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;commons-io&lt;/groupId&gt;
      &lt;artifactId&gt;commons-io&lt;/artifactId&gt;
      &lt;version&gt;1.4&lt;/version&gt;
      &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;commons-lang&lt;/groupId&gt;
      &lt;artifactId&gt;commons-lang&lt;/artifactId&gt;
      &lt;version&gt;2.5&lt;/version&gt;
      &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;commons-logging&lt;/groupId&gt;
      &lt;artifactId&gt;commons-logging&lt;/artifactId&gt;
      &lt;version&gt;1.1.1&lt;/version&gt;
      &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;dom4j&lt;/groupId&gt;
      &lt;artifactId&gt;dom4j&lt;/artifactId&gt;
      &lt;version&gt;1.6.1&lt;/version&gt;
      &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;net.sf.ehcache&lt;/groupId&gt;
      &lt;artifactId&gt;ehcache-core&lt;/artifactId&gt;
      &lt;version&gt;2.0.0&lt;/version&gt;
      &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;net.sf.ezmorph&lt;/groupId&gt;
      &lt;artifactId&gt;ezmorph&lt;/artifactId&gt;
      &lt;version&gt;1.0.3&lt;/version&gt;
      &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;org.codehaus.groovy&lt;/groupId&gt;
      &lt;artifactId&gt;groovy-all&lt;/artifactId&gt;
      &lt;version&gt;1.7.1&lt;/version&gt;
      &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;com.google.code.gson&lt;/groupId&gt;
      &lt;artifactId&gt;gson&lt;/artifactId&gt;
      &lt;version&gt;1.4&lt;/version&gt;
      &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;org.hibernate&lt;/groupId&gt;
      &lt;artifactId&gt;hibernate-core&lt;/artifactId&gt;
      &lt;version&gt;3.5.6-Final&lt;/version&gt;
      &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;org.hibernate&lt;/groupId&gt;
      &lt;artifactId&gt;hibernate-annotations&lt;/artifactId&gt;
      &lt;version&gt;3.5.6-Final&lt;/version&gt;
      &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;org.hibernate&lt;/groupId&gt;
      &lt;artifactId&gt;hibernate-commons-annotations&lt;/artifactId&gt;
      &lt;version&gt;3.2.0.Final&lt;/version&gt;
      &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;org.hibernate&lt;/groupId&gt;
      &lt;artifactId&gt;hibernate-entitymanager&lt;/artifactId&gt;
      &lt;version&gt;3.5.6-Final&lt;/version&gt;
      &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;org.hibernate.javax.persistence&lt;/groupId&gt;
      &lt;artifactId&gt;hibernate-jpa-2.0-api&lt;/artifactId&gt;
      &lt;version&gt;1.0.0.Final&lt;/version&gt;
      &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;!-- This lib must be added to your repository (comes from Sourceforge)--&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;hsqldb&lt;/groupId&gt;
      &lt;artifactId&gt;hsqldb&lt;/artifactId&gt;
      &lt;version&gt;1.8.1.2&lt;/version&gt;
      &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;!-- This lib must be added to your repository (comes from Sourceforge)--&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;com.jamonapi&lt;/groupId&gt;
      &lt;artifactId&gt;jamon&lt;/artifactId&gt;
      &lt;version&gt;2.7&lt;/version&gt;
      &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;javax.mail&lt;/groupId&gt;
      &lt;artifactId&gt;mail&lt;/artifactId&gt;
      &lt;version&gt;1.4.3&lt;/version&gt;
      &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;javassist&lt;/groupId&gt;
      &lt;artifactId&gt;javassist&lt;/artifactId&gt;
      &lt;version&gt;3.9.0.GA&lt;/version&gt;
      &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;jaxen&lt;/groupId&gt;
      &lt;artifactId&gt;jaxen&lt;/artifactId&gt;
      &lt;version&gt;1.1&lt;/version&gt;
      &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;!-- This lib must be added to your repository --&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;org.play.jj&lt;/groupId&gt;
      &lt;artifactId&gt;imaging&lt;/artifactId&gt;
      &lt;version&gt;1.1&lt;/version&gt;
      &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;!-- This lib must be added to your repository --&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;org.play.jj&lt;/groupId&gt;
      &lt;artifactId&gt;simple-captcha&lt;/artifactId&gt;
      &lt;version&gt;1.1&lt;/version&gt;
      &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;!-- This lib must be added to your repository --&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;org.play.jj&lt;/groupId&gt;
      &lt;artifactId&gt;textile&lt;/artifactId&gt;
      &lt;version&gt;1.1&lt;/version&gt;
      &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;!-- This lib must be added to your repository --&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;org.play.jj&lt;/groupId&gt;
      &lt;artifactId&gt;wikitext&lt;/artifactId&gt;
      &lt;version&gt;1.1&lt;/version&gt;
      &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;joda-time&lt;/groupId&gt;
      &lt;artifactId&gt;joda-time&lt;/artifactId&gt;
      &lt;version&gt;1.6&lt;/version&gt;
      &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;!-- This lib must be added to your repository (comes from Sourceforge)--&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;jregex&lt;/groupId&gt;
      &lt;artifactId&gt;jregex&lt;/artifactId&gt;
      &lt;version&gt;1.2_01&lt;/version&gt;
      &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;net.sf.jsr107cache&lt;/groupId&gt;
      &lt;artifactId&gt;jsr107cache&lt;/artifactId&gt;
      &lt;version&gt;1.0&lt;/version&gt;
      &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;javax.transaction&lt;/groupId&gt;
      &lt;artifactId&gt;jta&lt;/artifactId&gt;
      &lt;version&gt;1.1&lt;/version&gt;
      &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;junit&lt;/groupId&gt;
      &lt;artifactId&gt;junit&lt;/artifactId&gt;
      &lt;version&gt;4.8.1&lt;/version&gt;
      &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;log4j&lt;/groupId&gt;
      &lt;artifactId&gt;log4j&lt;/artifactId&gt;
      &lt;version&gt;1.2.16&lt;/version&gt;
      &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;!-- This lib must be added to your repository --&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;net.spy&lt;/groupId&gt;
      &lt;artifactId&gt;memcached&lt;/artifactId&gt;
      &lt;version&gt;2.4.2&lt;/version&gt;
      &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;mysql&lt;/groupId&gt;
      &lt;artifactId&gt;mysql-connector-java&lt;/artifactId&gt;
      &lt;version&gt;5.1.13&lt;/version&gt;
      &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;org.jboss.netty&lt;/groupId&gt;
      &lt;artifactId&gt;netty&lt;/artifactId&gt;
      &lt;version&gt;3.2.2.Final&lt;/version&gt;
      &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;!-- This lib must be added to your repository --&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;org.play&lt;/groupId&gt;
      &lt;artifactId&gt;org.eclipse.jdt.core&lt;/artifactId&gt;
      &lt;version&gt;3.6.0&lt;/version&gt;
      &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;net.sf.oval&lt;/groupId&gt;
      &lt;artifactId&gt;oval&lt;/artifactId&gt;
      &lt;version&gt;1.50&lt;/version&gt;
      &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;org.apache.geronimo.specs&lt;/groupId&gt;
      &lt;artifactId&gt;geronimo-servlet_2.5_spec&lt;/artifactId&gt;
      &lt;version&gt;1.2&lt;/version&gt;
      &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;oauth.signpost&lt;/groupId&gt;
      &lt;artifactId&gt;signpost-core&lt;/artifactId&gt;
      &lt;version&gt;1.2&lt;/version&gt;
      &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;org.slf4j&lt;/groupId&gt;
      &lt;artifactId&gt;slf4j-api&lt;/artifactId&gt;
      &lt;version&gt;1.6.1&lt;/version&gt;
      &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;org.slf4j&lt;/groupId&gt;
      &lt;artifactId&gt;slf4j-log4j12&lt;/artifactId&gt;
      &lt;version&gt;1.6.1&lt;/version&gt;
      &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;org.yaml&lt;/groupId&gt;
      &lt;artifactId&gt;snakeyaml&lt;/artifactId&gt;
      &lt;version&gt;1.6&lt;/version&gt;
      &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;
    
    &lt;!-- Play! framework dependency --&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;org.play&lt;/groupId&gt;
      &lt;artifactId&gt;play&lt;/artifactId&gt;
      &lt;version&gt;1.1&lt;/version&gt;
    &lt;/dependency&gt;
    
    &lt;dependency&gt;
      &lt;groupId&gt;org.play&lt;/groupId&gt;
      &lt;artifactId&gt;play-runtime&lt;/artifactId&gt;
      &lt;version&gt;1.1&lt;/version&gt;
      &lt;type&gt;zip&lt;/type&gt;
    &lt;/dependency&gt;
  &lt;/dependencies&gt;
  
  &lt;build&gt;
    &lt;sourceDirectory&gt;app&lt;/sourceDirectory&gt;
    &lt;pluginManagement&gt;
      &lt;plugins&gt;
        &lt;plugin&gt;
          &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
          &lt;artifactId&gt;maven-war-plugin&lt;/artifactId&gt;
          &lt;version&gt;2.1.1&lt;/version&gt;
          &lt;configuration&gt;
            &lt;failOnMissingWebXml&gt;false&lt;/failOnMissingWebXml&gt;
          &lt;/configuration&gt;
        &lt;/plugin&gt;

        &lt;plugin&gt;
          &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
          &lt;artifactId&gt;maven-dependency-plugin&lt;/artifactId&gt;
          &lt;version&gt;2.1&lt;/version&gt;
          &lt;executions&gt;
            &lt;execution&gt;
              &lt;id&gt;default-cli&lt;/id&gt;
              &lt;configuration&gt;
                &lt;includeClassifiers&gt;,sources&lt;/includeClassifiers&gt;
                &lt;outputDirectory&gt;lib/&lt;/outputDirectory&gt;
                &lt;excludeScope&gt;provided&lt;/excludeScope&gt;
                &lt;!-- To download sources jars without failing --&gt;
                &lt;failOnMissingClassifierArtifact&gt;false&lt;/failOnMissingClassifierArtifact&gt;
                &lt;excludeArtifactIds&gt;play-runtime,play&lt;/excludeArtifactIds&gt;
              &lt;/configuration&gt;
            &lt;/execution&gt;
            &lt;execution&gt;
              &lt;id&gt;packaging&lt;/id&gt;
              &lt;phase&gt;package&lt;/phase&gt;
              &lt;goals&gt;
                &lt;goal&gt;copy-dependencies&lt;/goal&gt;
              &lt;/goals&gt;
              &lt;configuration&gt;
                &lt;includeArtifactIds&gt;play-runtime&lt;/includeArtifactIds&gt;
              &lt;/configuration&gt;
            &lt;/execution&gt;
          &lt;/executions&gt;
        &lt;/plugin&gt;

        &lt;plugin&gt;
          &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
          &lt;artifactId&gt;maven-antrun-plugin&lt;/artifactId&gt;
          &lt;version&gt;1.6&lt;/version&gt;
          &lt;executions&gt;
            &lt;execution&gt;
              &lt;phase&gt;package&lt;/phase&gt;
              &lt;configuration&gt;
                &lt;target&gt;
                  &lt;property name=&quot;maven.project.artifactId&quot; value=&quot;${project.artifactId}&quot; /&gt;
                  &lt;property name=&quot;maven.project.version&quot; value=&quot;${project.version}&quot; /&gt;
                  &lt;property name=&quot;maven.project.play-runtime&quot; value=&quot;play-runtime-${play.version}&quot; /&gt;

                  &lt;property name=&quot;play.runtime.path&quot; value=&quot;${basedir}/target/dependency/${maven.project.play-runtime}&quot; /&gt;
                  &lt;property name=&quot;play.runtime.file&quot; value=&quot;${basedir}/target/dependency/${maven.project.play-runtime}.zip&quot; /&gt;
                  &lt;property name=&quot;play.runtime.unzip.path&quot; value=&quot;${basedir}/target/dependency&quot; /&gt;

                  &lt;!-- Check zipped Play! runtime is present. Build fails if not present --&gt;
                  &lt;available file=&quot;${play.runtime.file}&quot; property=&quot;play.runtime.present&quot; /&gt;
                  &lt;echo message=&quot;Is Play! runtime present : ${play.runtime.present}&quot; /&gt;

                  &lt;fail message=&quot;Error : Play! runtime could not be found at : ${play.runtime.file}&quot;&gt;
                    &lt;condition&gt;
                      &lt;not&gt;
                        &lt;isset property=&quot;play.runtime.present&quot; /&gt;
                      &lt;/not&gt;
                    &lt;/condition&gt;
                  &lt;/fail&gt;

                  &lt;!-- Delete existing Play! runtime --&gt;
                  &lt;echo message=&quot;Deleting any existing unzipped Play! runtime ...&quot; /&gt;
                  &lt;delete dir=&quot;play.runtime.unzip.path&quot; failonerror=&quot;false&quot; verbose=&quot;true&quot; /&gt;

                  &lt;!-- Unzip Play! runtime --&gt;
                  &lt;echo message=&quot;Unzipping Play! runtime ...&quot; /&gt;
                  &lt;unzip src=&quot;${play.runtime.file}&quot; dest=&quot;${play.runtime.unzip.path}&quot; /&gt;
                  &lt;echo message=&quot;Play! runtime unzipped successfully.&quot; /&gt;
                  &lt;chmod dir=&quot;${play.runtime.path}&quot; perm=&quot;ugo+x&quot; includes=&quot;play&quot; /&gt;

                  &lt;!-- launch play mvn:up to retrieve libs in /lib folder --&gt;
                  &lt;condition property=&quot;playExtension&quot; value=&quot;.bat&quot;&gt;
                    &lt;and&gt;
                      &lt;os family=&quot;windows&quot; /&gt;
                    &lt;/and&gt;
                  &lt;/condition&gt;
                  &lt;condition property=&quot;playExtension&quot; value=&quot;&quot;&gt;
                    &lt;and&gt;
                      &lt;os family=&quot;unix&quot; /&gt;
                    &lt;/and&gt;
                  &lt;/condition&gt;
                  &lt;exec executable=&quot;${play.runtime.unzip.path}/${maven.project.play-runtime}/play${playExtension}&quot;&gt;
                    &lt;arg value=&quot;mvn:up&quot; /&gt;
                  &lt;/exec&gt;

                  &lt;!-- Launch Play war command --&gt;
                  &lt;condition property=&quot;playExtension&quot; value=&quot;.bat&quot;&gt;
                    &lt;and&gt;
                      &lt;os family=&quot;windows&quot; /&gt;
                    &lt;/and&gt;
                  &lt;/condition&gt;
                  &lt;condition property=&quot;playExtension&quot; value=&quot;&quot;&gt;
                    &lt;and&gt;
                      &lt;os family=&quot;unix&quot; /&gt;
                    &lt;/and&gt;
                  &lt;/condition&gt;
                  &lt;exec executable=&quot;${play.runtime.unzip.path}/${maven.project.play-runtime}/play${playExtension}&quot;&gt;
                    &lt;arg value=&quot;war&quot; /&gt;
                    &lt;arg value=&quot;${basedir}&quot; /&gt;
                    &lt;arg value=&quot;-o&quot; /&gt;
                    &lt;arg value=&quot;${basedir}/target/${maven.project.artifactId}-${maven.project.version}&quot; /&gt;
                    &lt;arg value=&quot;--zip&quot; /&gt;
                  &lt;/exec&gt;
                &lt;/target&gt;
              &lt;/configuration&gt;
              &lt;goals&gt;
                &lt;goal&gt;run&lt;/goal&gt;
              &lt;/goals&gt;
            &lt;/execution&gt;
          &lt;/executions&gt;
        &lt;/plugin&gt;

        &lt;plugin&gt;
          &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
          &lt;artifactId&gt;maven-clean-plugin&lt;/artifactId&gt;
          &lt;version&gt;2.4.1&lt;/version&gt;
          &lt;configuration&gt;
            &lt;filesets&gt;
              &lt;fileset&gt;
                &lt;directory&gt;${project.basedir}/lib&lt;/directory&gt;
                &lt;includes&gt;
                  &lt;include&gt;**/*.jar&lt;/include&gt;
                  &lt;include&gt;**/*.zip&lt;/include&gt;
                &lt;/includes&gt;
                &lt;followSymlinks&gt;false&lt;/followSymlinks&gt;
              &lt;/fileset&gt;
            &lt;/filesets&gt;
          &lt;/configuration&gt;
        &lt;/plugin&gt;
        
        &lt;plugin&gt;
          &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
          &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;
          &lt;version&gt;2.3.1&lt;/version&gt;
          &lt;configuration&gt;
            &lt;source&gt;1.5&lt;/source&gt;
            &lt;target&gt;1.5&lt;/target&gt;
          &lt;/configuration&gt;
        &lt;/plugin&gt;

      &lt;/plugins&gt;
    &lt;/pluginManagement&gt;

  &lt;/build&gt;
  
&lt;/project&gt;
</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.infin-it.fr/2010/12/15/play-framework-integration-continue-retour-dexperience/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Aggrégateur JMX</title>
		<link>http://blog.infin-it.fr/2010/08/05/aggregateur-jmx-2/</link>
		<comments>http://blog.infin-it.fr/2010/08/05/aggregateur-jmx-2/#comments</comments>
		<pubDate>Thu, 05 Aug 2010 10:28:54 +0000</pubDate>
		<dc:creator><![CDATA[Jean-Philippe Briend]]></dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[JMX]]></category>
		<category><![CDATA[Spring]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[JMX JSR-250]]></category>

		<guid isPermaLink="false">http://blog.infin-it.fr/?p=219</guid>
		<description><![CDATA[JMX (Java Management Extensions) est très pratique pour le monitoring d&#8217;une application. Malheureusement, lorsque l&#8217;application grandit et que, par exemple, des traitements nocturnes apparaissent, ces derniers tournent dans des machines virtuelles distinctes. A ce moment là, JMX pose problème pour la remontée d&#8217;informations. L&#8217;idée que je vais vous proposer est la suivante : Une JVM [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>JMX (Java Management Extensions) est très pratique pour le monitoring d&#8217;une application.<br />
Malheureusement, lorsque l&#8217;application grandit et que, par exemple, des traitements nocturnes apparaissent, ces derniers tournent dans des machines virtuelles distinctes.</p>
<p>A ce moment là, JMX pose problème pour la remontée d&#8217;informations.</p>
<p>L&#8217;idée que je vais vous proposer est la suivante :</p>
<ul>
<li>Une JVM hébergeant un MBeanServer tourne en continu (éventuellement hébergé dans un serveur d&#8217;application).</li>
<li>Chacun des traitements se connectera à cette JVM en utilisant un <a href="http://java.sun.com/j2se/1.5.0/docs/guide/jmx/tutorial/connectors.html">JMX Connector</a> et invoquera à distance des Notifications JMX à destination du MBeanServer.</li>
</ul>
<p><span id="more-219"></span></p>
<p>Grâce à cette architecture, les ports des JVM &#8216;clientes&#8217; ne sont plus un problème : on laisse le mécanisme par défaut de JMX se débrouiller pour en trouver un libre.</p>
<p>Les personnes souhaitant monitorer ces traitements n&#8217;ont qu&#8217;à lancer JConsole et se connecter sur la JVM &#8216;serveur&#8217; qui héberge le MBeanServer.</p>
<p>Le schéma suivant présente le principe :</p>
<p><a href="http://blog.infin-it.fr/wp-content/uploads/2010/03/Aggregateur-JMX.png"><img src="http://blog.infin-it.fr/wp-content/uploads/2010/03/Aggregateur-JMX-300x107.png" alt="" title="Aggregateur JMX" width="300" height="107" class="aligncenter size-medium wp-image-57" /><center>Cliquez pour agrandir</center></a></p>
<p>JMX Notifier va être un objet faisant appel au NotificationPublisher de JMX.<br />
Ce NotificationPublisher envoi des notifications au serveur MBean.</p>
<p>Le JMX Notifier va être exposé par des JMX Connectors aux clients et sera proxyfié.<br />
Le traitement peut alors utiliser de façon invisible cet objet pour envoyer des évènements à la JVM distante.</p>
<p>Passons maintenant au code !</p>
<p><u>JMX Notifier (serveur) :</u><br />
<font size="3"></p>
<pre class="brush: java; title: ; wrap-lines: false; notranslate">
@ManagedResource(objectName=&quot;batch:name=BatchJMX&quot;, description=&quot;JMX Notifier&quot;)
public class JmxNotifierImpl implements JmxNotifier, NotificationPublisherAware {

  protected NotificationPublisher publisher;

  @ManagedOperation(description=&quot;Annonce Début batch.&quot;)
  @ManagedOperationParameters(
  @ManagedOperationParameter(name=&quot;id&quot;, description= &quot;Batch ID.&quot;))
  public void annonceDebut(String id) {
    super.publisher.sendNotification(
                    new Notification(&quot;Debut du Batch &quot; + id,
                                           this,
                                           0,
                                           Calendar.getInstance().getTimeInMillis()));
  }

  public void setNotificationPublisher(NotificationPublisher publisher) {
    this.publisher = publisher;
  }
}
</pre>
<p></font><br />
On notera l&#8217;utilisation de l&#8217;interface <a href="http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/jmx/export/notification/NotificationPublisherAware.html">NotificationPublisherAware</a> afin de se faire injecter le <a href="http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/jmx/export/notification/NotificationPublisher.html">NotificationPublisher</a> par Spring.</p>
<p><u>JMX Notifier Service (client) :</u><br />
<font size="3"></p>
<pre class="brush: java; title: ; wrap-lines: false; notranslate">
public class JmxNotifierServiceImpl implements InitializingBean {
	
  private String objectName;
  private String url;
  private JMXConnector jmxConnector;
  private JmxNotifier notifier;
	
  public void afterPropertiesSet() {
    try {
      ObjectName objectName = new ObjectName(this.objectName);
      JMXServiceURL jmxUrl = new JMXServiceURL(this.url);
      this.jmxConnector = JMXConnectorFactory.connect(jmxUrl);
      MBeanServerConnection mbsc = this.jmxConnector.getMBeanServerConnection();

      this.notifier = (JmxNotifier)MBeanServerInvocationHandler.newProxyInstance(
                                                                                           mbsc,
                                                                                           objectName,
                                                                                           JmxNotifier.class,
                                                                                           false);
    } catch (MalformedObjectNameException e) {
      System.err.println(&quot;Warning : could not connect to 
                                     JMX server. JMX Notifications will not be sent.&quot;);
      System.err.println(&quot;Reason : &quot; + e.getMessage());
    } catch (MalformedURLException e) {
      System.err.println(&quot;Warning : could not connect to
                                     JMX server. JMX Notifications will not be sent.&quot;);
      System.err.println(&quot;Reason : &quot; + e.getMessage());
    } catch (IOException e) {
     System.err.println(&quot;Warning : could not connect to
                                     JMX server. JMX Notifications will not be sent.&quot;);
     System.err.println(&quot;It seems that remote server is
                                     not up and not running.&quot;);
    }
  }
}

  public void close() throws IOException {
    if ( this.jmxConnector != null ) {
      this.jmxConnector.close();
  }

  public void annonceDebu(String id) {
    if ( this.notifier != null ) {
      this.notifier.annonceDebut(id);
    }
  }
}
</pre>
<p></font><br />
Une meilleure gestion des exceptions levées permettrait de gérer les cas où le serveur distant n&#8217;est pas disponible.</p>
<p>Côté serveur, il va vous falloir la configuration Spring suivante :<br />
<font size="3"></p>
<pre class="brush: xml; title: ; notranslate">
&lt;context:annotation-config /&gt;

&lt;bean id=&quot;jmxNotifier&quot; class=&quot;JmxNotifierImpl&quot; /&gt;

&lt;bean id=&quot;registry&quot; class=&quot;org.springframework.remoting.rmi.RmiRegistryFactoryBean&quot; /&gt;

&lt;bean id=&quot;mbeanServer&quot; class=&quot;org.springframework.jmx.support.MBeanServerFactoryBean&quot;&gt;
	&lt;property name=&quot;locateExistingServerIfPossible&quot; value=&quot;true&quot; /&gt;
&lt;/bean&gt;

&lt;bean id=&quot;serverConnector&quot; class=&quot;org.springframework.jmx.support.ConnectorServerFactoryBean&quot;&gt;
  &lt;property name=&quot;objectName&quot; value=&quot;connector:name=rmi&quot;/&gt;
  &lt;property name=&quot;serviceUrl&quot; value=&quot;service:jmx:rmi://localhost/jndi/rmi://localhost:1099/standaloneJmxServer&quot;/&gt;
  &lt;property name=&quot;threaded&quot; value=&quot;true&quot;/&gt;
	&lt;property name=&quot;daemon&quot; value=&quot;true&quot;/&gt;
&lt;/bean&gt;
  
&lt;bean class=&quot;org.springframework.jmx.export.MBeanExporter&quot; lazy-init=&quot;false&quot;&gt;
	&lt;property name=&quot;autodetect&quot; value=&quot;true&quot; /&gt;
	&lt;property name=&quot;namingStrategy&quot; ref=&quot;namingStrategy&quot; /&gt;
	&lt;property name=&quot;assembler&quot; ref=&quot;assembler&quot; /&gt;
&lt;/bean&gt;

&lt;bean id=&quot;attributeSource&quot; class=&quot;org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource&quot;/&gt;

&lt;bean id=&quot;assembler&quot; class=&quot;org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler&quot;&gt;
	&lt;property name=&quot;attributeSource&quot; ref=&quot;attributeSource&quot; /&gt;
&lt;/bean&gt;

&lt;bean id=&quot;namingStrategy&quot; class=&quot;org.springframework.jmx.export.naming.MetadataNamingStrategy&quot;&gt;
	&lt;property name=&quot;attributeSource&quot; ref=&quot;attributeSource&quot; /&gt;
&lt;/bean&gt;
</pre>
<p></font></p>
<p>Les points marquants sont la présence de la MBeanServerFactory, la ConnectorServerFactoryBean et la RMIRegistryFactoryBean.</p>
<p>Et c&#8217;est tout !<br />
Votre code n&#8217;a plus qu&#8217;à appeler JMXNotifierService.<br />
Après, à vous d&#8217;enrichir les 2 JMX Notifier en fonction du fonctionnel de votre application.</p>
<p>Les équipes responsables du monitoring n&#8217;ont qu&#8217;à connecter leur JConsole sur la JVM contenant le MBeanServer.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.infin-it.fr/2010/08/05/aggregateur-jmx-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Sample : génération de document PDF avec iText (1ère partie)</title>
		<link>http://blog.infin-it.fr/2010/08/05/sample-generation-de-document-pdf-avec-itext-1ere-partie/</link>
		<comments>http://blog.infin-it.fr/2010/08/05/sample-generation-de-document-pdf-avec-itext-1ere-partie/#comments</comments>
		<pubDate>Thu, 05 Aug 2010 09:51:36 +0000</pubDate>
		<dc:creator><![CDATA[Jean-Philippe Briend]]></dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[exemple]]></category>
		<category><![CDATA[itext]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[pdf]]></category>

		<guid isPermaLink="false">http://blog.infin-it.fr/?p=179</guid>
		<description><![CDATA[Après avoir étudié les différents frameworks Java en vue de la génération de documents PDF (ici), entrainons-nous maintenant 2 exemples simples d&#8217;implémentation de la librairie iText. Ce sample se divise en 2 parties : la 1ère montre un exemple de génération de document PDF from scratch. la 2ième partie va générer un document à partir [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Après avoir étudié les différents frameworks Java en vue de la génération de documents PDF (<a class="vt-p" href="http://blog.infin-it.fr/2010/07/20/comparatif-des-librairies-java-pour-pdf/" target="_blank">ici</a>), entrainons-nous maintenant 2 exemples simples d&#8217;implémentation de la librairie <a class="vt-p" href="http://www.itextpdf.com/" target="_blank">iText</a>.</p>
<p>Ce sample se divise en 2 parties :</p>
<ul>
<li>la 1ère montre un exemple de génération de document PDF from scratch.</li>
<li>la 2ième partie va générer un document à partir d&#8217;un template que nous allons créer dans Open-Office.</li>
</ul>
<p><span id="more-179"></span></p>
<h3><span style="text-decoration: underline;">Générer un document PDF &#8216;from scratch&#8217; :</span></h3>
<ul>
<li><span style="text-decoration: underline;">1ère étape : générer un projet Java.</span></li>
</ul>
<p>Pour cela, utilisons la commande <em>mvn archetype:generate</em> et choisissons de créer un <em>maven-archetype-quickstart</em>.<br />
Dans notre exemple, le projet est configuré comme suit :</p>
<p><font size="3"></p>
<pre class="brush: xml; title: ; notranslate">
  &lt;groupId&gt;fr.infinit.sample.generationpdf&lt;/groupId&gt;
  &lt;artifactId&gt;generationpdf&lt;/artifactId&gt;
  &lt;version&gt;1.0.0-SNAPSHOT&lt;/version&gt;
  &lt;name&gt;Sample Generation PDF&lt;/name&gt;
</pre>
<p></font><br />
<HR/></p>
<ul>
<li><span style="text-decoration: underline;">2ième étape : ajouter la dépendance Maven à iText.</span></li>
</ul>
<p>Ajoutons le repository iText ainsi que la dépendance pour iText :</p>
<p><font size="3"></p>
<pre class="brush: xml; title: ; notranslate">
&lt;repositories&gt;
  &lt;repository&gt;
    &lt;id&gt;itextpdf.com&lt;/id&gt;
    &lt;name&gt;Maven Repository for iText&lt;/name&gt;
    &lt;url&gt;http://maven.itextpdf.com/&lt;/url&gt;
  &lt;/repository&gt;
&lt;/repositories&gt;
</pre>
<pre class="brush: xml; title: ; notranslate">
&lt;dependencies&gt;
  &lt;dependency&gt;
    &lt;groupId&gt;com.itextpdf&lt;/groupId&gt;
    &lt;artifactId&gt;itextpdf&lt;/artifactId&gt;
    &lt;version&gt;5.0.2&lt;/version&gt;
    &lt;scope&gt;compile&lt;/scope&gt;
  &lt;/dependency&gt;
&lt;/dependencies&gt;
</pre>
<p></font><br />
<HR/></p>
<ul>
<li><span style="text-decoration: underline;">3ième étape : Créer un document PDF vide.</span></li>
</ul>
<p>Nous allons utiliser la classe <strong>com.itextpdf.text.Document</strong> :</p>
<p><font size="3"></p>
<pre class="brush: java; title: ; wrap-lines: false; notranslate">
    /**
     * Crée un Document vide.
     *
     * @param file Chemin du fichier à créer.
     * @return Document s'il n'y a pas eu d'erreur.
     * @throws IOException s'il y a eu une erreur avec le nom de fichier fourni.
     * @throws DocumentException s'il y a eu une erreur côté iText.
     */
    private Document creerDocument(String file) throws DocumentException, IOException {
        Document document = new Document();

        PdfWriter pdfWriter = PdfWriter.getInstance(document, new FileOutputStream(file));
        pdfWriter.setPageEvent(this);
        // Préférence de lecture : 2 pages en colonne.
        pdfWriter.setViewerPreferences(PdfWriter.PageLayoutTwoColumnLeft);
        document.open();

        return document;
    }
</pre>
<p></font></p>
<p>Attention à ne pas oublier de fermer l&#8217;objet Document après avoir travaillé sur cet objet !<br />
<HR/></p>
<ul>
<li><span style="text-decoration: underline;">4ième étape : Ajouter des informations Metadata.</span></li>
</ul>
<p>L&#8217;ajout de ces informations se fait via la classe <strong>com.itextpdf.text.Document</strong> :</p>
<p><font size="3"></p>
<pre class="brush: java; title: ; wrap-lines: false; notranslate">
    /**
     * Ajout de données de type Metadata au document.
     *
     * @param document Document auquel il faut rajouter les metadatas.
     */
    private void addMetaData(Document document) {
        document.addTitle(&quot;Sample PDF&quot;);
        document.addSubject(&quot;Utilisant iText&quot;);
        document.addKeywords(&quot;Java, PDF, iText&quot;);
        document.addAuthor(System.getProperty(&quot;user.name&quot;));
        document.addCreator(System.getProperty(&quot;user.name&quot;));
    }
</pre>
<p></font><br />
<HR/></p>
<ul>
<li><span style="text-decoration: underline;">5ième étape : Ajouter des lignes vides.</span></li>
</ul>
<p>L&#8217;ajout de lignes vides se fait en ajoutant des paragraphes avec des espaces :</p>
<p><font size="3"></p>
<pre class="brush: java; title: ; wrap-lines: false; notranslate">
    /**
     * Ajoute une ligne vide number fois dans le Paragraph passé en paramètre.
     *
     * @param paragraph A remplir avec les lignes vides.
     * @param number Nombre de lignes vides à ajouter.
     */
    private void ajouterLigneVide(Paragraph paragraph, int number) {
        for (int i = 0; i &lt; number; i++) {
            paragraph.add(new Paragraph(&quot; &quot;));
        }
    }
</pre>
<p></font><br />
<HR/></p>
<ul>
<li><span style="text-decoration: underline;">6ième étape : Ajouter des paragraphes avec des polices différentes.</span></li>
</ul>
<p>Commençons par définir différentes polices :<br />
<font size="3"></p>
<pre class="brush: java; title: ; wrap-lines: false; notranslate">
    /** Times Roman 18 Bold */
    private static final Font CATFONT = new Font(Font.getFamily(&quot;TIMES_ROMAN&quot;), 18, Font.BOLD);

    /** Times Roman 12 Normal */
    private static final Font REDFONT = new Font(Font.getFamily(&quot;TIMES_ROMAN&quot;), 12, Font.NORMAL);

    /** Times Roman 16 Bold */
    private static final Font SUBFONT = new Font(Font.getFamily(&quot;TIMES_ROMAN&quot;), 16, Font.BOLD);

    /** Times Roman 12 Bold */
    private static final Font SMALLBOLD = new Font(Font.getFamily(&quot;TIMES_ROMAN&quot;), 12, Font.BOLD);
</pre>
<p></font></p>
<p>Ensuite, ajoutons différents paragraphes à notre document :<br />
<font size="3"></p>
<pre class="brush: java; title: ; wrap-lines: false; notranslate">
    /**
     * Ajoute 4 paragraphes / - Titre du document. - Rapport généré par ... - Ce
     * document décrit ... - Ce document est ...
     *
     * @param document Document à enrichir
     * @throws DocumentException Si un problème survient lors de l'ajout des
     *             données.
     */
    private void addTitlePage(Document document) throws DocumentException {
        Paragraph preface = new Paragraph();

        // Ajout d'une ligne vide
        ajouterLigneVide(preface, 1);

        // Ecriture du header
        preface.add(new Paragraph(&quot;Titre du document&quot;, CATFONT));
        ajouterLigneVide(preface, 1);

        preface.add(new Paragraph(&quot;Rapport généré par: &quot; + System.getProperty(&quot;user.name&quot;) + &quot;, &quot; + new Date(), SMALLBOLD));
        ajouterLigneVide(preface, 3);

        preface.add(new Paragraph(&quot;Ce document décrit quelque chose de très important &quot;, SMALLBOLD));
        ajouterLigneVide(preface, 8);

        preface.add(new Paragraph(&quot;Ce document est une version préliminaire et n'est sujet à aucune restriction.&quot;, REDFONT));
        document.add(preface);

        // Debut d'une nouvelle page
        document.newPage();
    }
</pre>
<p></font></p>
<p><HR/></p>
<ul>
<li><span style="text-decoration: underline;">7ième étape : Ajouter du contenu (Chapitre, Section, Sous-section, Anchor).</span></li>
</ul>
<p>Les objets Anchor, Chapter, Section permettent de définir différentes zones de contenu dans un document.<br />
<font size="3"></p>
<pre class="brush: java; title: ; wrap-lines: false; notranslate">
Anchor anchor = new Anchor(&quot;Premier Chapitre&quot;, CATFONT);
anchor.setName(&quot;Premier Chapitre&quot;);

// Le 2ième paramètre est le numero du chapitre
Chapter catPart = new Chapter(new Paragraph(anchor), 1);

Paragraph subPara = new Paragraph(&quot;Sous-Catégorie 1&quot;, SUBFONT);
Section subCatPart = catPart.addSection(subPara);
subCatPart.add(new Paragraph(&quot;Coucou (pour ne pas mettre toto...).&quot;));

subPara = new Paragraph(&quot;Sous-catégorie 2&quot;, SUBFONT);
subCatPart = catPart.addSection(subPara);
subCatPart.add(new Paragraph(&quot;Paragraphe 1&quot;));
subCatPart.add(new Paragraph(&quot;Paragraphe 2&quot;));
subCatPart.add(new Paragraph(&quot;Paragraphe 3&quot;));
</pre>
<p></font></p>
<hr/>
<ul>
<li><span style="text-decoration: underline;">8ième étape : Ajouter un tableau.</span></li>
</ul>
<p>Un tableau se créé avec la classe <b>com.itextpdf.text.pdf.PdfPTable</b>.<br />
Il se compose de <b>com.itextpdf.text.pdf.PdfPCell</b> :<br />
<font size="3"></p>
<pre class="brush: java; title: ; wrap-lines: false; notranslate">
/**
 * Crée un tableau de 3 colonnes et l'ajoute à la Section passée en
 * paramètre.
 * 
 * @param subCatPart Section à remplir avec le tableau.
 * @throws BadElementException Si une erreur survient lors de l'ajout d'un
 *             élément dans la PdfPTable.
 */
private void createTable(Section subCatPart) throws BadElementException {
    // Creation d'une PdfPTable avec 3 colonnes
    final PdfPTable table = new PdfPTable(3);

    // Creation d'une PdfPCell avec un paragraphe
    final PdfPCell cell = new PdfPCell(new Paragraph(&quot;header with colspan 3&quot;));

    // Changement du colspan de la PdfCell
    cell.setColspan(3);

    // Ajout de la PdfCell custom à la PdfPTable
    table.addCell(cell);

    // Ajout d'objets String à la PdfPTable
    table.addCell(&quot;1.1&quot;);
    table.addCell(&quot;2.1&quot;);
    table.addCell(&quot;3.1&quot;);
    table.addCell(&quot;1.2&quot;);
    table.addCell(&quot;2.2&quot;);
    table.addCell(&quot;3.2&quot;);

    // Ajout d'un espace entre la PdfPTable et l'élément précédent.
    table.setSpacingBefore(15f);

    subCatPart.add(table);
}
</pre>
<p></font></p>
<hr/>
<ul>
<li><span style="text-decoration: underline;">9ième étape : Ajouter une liste à puce.</span></li>
</ul>
<p>Une liste à puce dans un document PDF se créé avec l&#8217;objet <b>com.itextpdf.text.List</b>.<br />
En voici un exemple :<br />
<font size="3"></p>
<pre class="brush: java; title: ; wrap-lines: false; notranslate">
/**
 * Crée une liste et l'ajoute dans la Section passée en paramètre.
 * 
 * @param subCatPart Section à remplir avec la liste.
 */
private void createList(Section subCatPart) {
    final List list = new List(true, false, 10);
    list.add(new ListItem(&quot;Premier point&quot;));
    list.add(new ListItem(&quot;Deuxième point&quot;));
    list.add(new ListItem(&quot;Troisième point&quot;));
    subCatPart.add(list);
}
</pre>
<p></font></p>
<hr/>
<ul>
<li><span style="text-decoration: underline;">10ième étape : Ajouter des numéros de pages.</span></li>
</ul>
<p>L&#8217;ajout des numéros de page se fait en utilisant la classe <b>com.itextpdf.text.pdf.PdfPageEventHelper</b>.<br />
Elle s&#8217;utilise en l&#8217;ajoutant comme PageEvent sur le PdfWriter (méthode setPageEvent).<br />
Il suffit ensuite de surcharger les méthodes que l&#8217;on souhaite utiliser : onOpenDocument, onEndPage, etc&#8230;</p>
<p>Dans notre exemple, la méthode onOpenDocument est utilisée pour créer un <b>com.itextpdf.text.pdf.PdfTemplate</b> qui contiendra le texte des numéros de page.<br />
<font size="3"></p>
<pre class="brush: java; title: ; wrap-lines: false; notranslate">
/**
 * Création du template destiné à recevoir les numéros de page.
 * 
 * @param writer PdfWriter à utiliser.
 * @param document Document à enrichir.
 */
@Override
public void onOpenDocument(PdfWriter writer, Document document) {
    total = writer.getDirectContent().createTemplate(100, 100);
    total.setBoundingBox(new Rectangle(-20, -20, 100, 100));
    try {
        helv = BaseFont.createFont(BaseFont.HELVETICA, BaseFont.WINANSI, BaseFont.NOT_EMBEDDED);
    } catch (DocumentException e) {
        LOG.error(e.getMessage(), e);
        // TODO : gérer l'exception.
    } catch (IOException e) {
        LOG.error(e.getMessage(), e);
        // TODO : gérer l'exception.
    }
}
</pre>
<p></font></p>
<p>Note : total est un <b>com.itextpdf.text.pdf.PdfTemplate</b>.</p>
<p>La méthode onEndPage est responsable du remplissage du PdfTemplate pour chaque page via un <b>com.itextpdf.text.pdf.PdfContentByte</b>.</p>
<p>Dans l&#8217;exemple suivant, les numéros de page paires sont écrits en bas à gauche et les impaires sont écrits en bas à droite :<br />
<font size="3"></p>
<pre class="brush: java; title: ; wrap-lines: false; notranslate">
/**
 * Ajoute des numeros de page automatiquement. Les numeros paires sont mis
 * en bas à gauche. Les numéros impaires sont mis en bas à droite.
 * 
 * @param writer Pdfwriter à utiliser.
 * @param document Document à utiliser.
 */
@Override
public void onEndPage(PdfWriter writer, Document document) {
    LOG.info(&quot;Generation des numeros de page ...&quot;);
    final PdfContentByte directcontent = writer.getDirectContent();

    directcontent.saveState();
    final String text = &quot;Page &quot; + writer.getPageNumber();
    final float textBase = document.bottom() - 20;
    final float textSize = helv.getWidthPoint(text, 12);

    directcontent.beginText();
    directcontent.setFontAndSize(helv, 11);

    // Ecriture du numero de page a gauche pour les pages impaires.
    if ((writer.getPageNumber() % 2) == 1) {
        directcontent.setTextMatrix(document.left(), textBase);
        directcontent.showText(text);
        directcontent.endText();
        directcontent.addTemplate(total, document.left() + textSize, textBase);
    } else {
        // Ecriture du numero de page a droite pour les pages paires.
        final float adjust = helv.getWidthPoint(&quot;0&quot;, 12);
        directcontent.setTextMatrix(document.right() - textSize - adjust, textBase);
        directcontent.showText(text);
        directcontent.endText();
        directcontent.addTemplate(total, document.right() - adjust, textBase);
    }
    directcontent.restoreState();
}
</pre>
<p></font></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.infin-it.fr/2010/08/05/sample-generation-de-document-pdf-avec-itext-1ere-partie/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

<!-- Dynamic page generated in 0.726 seconds. -->
<!-- Cached page generated by WP-Super-Cache on 2014-08-31 03:51:08 -->

<!-- Compression = gzip -->