<?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>Le Touilleur Express &#187; groovy</title>
	<atom:link href="http://www.touilleur-express.fr/category/groovy/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.touilleur-express.fr</link>
	<description>Blog sur Java, le métier de développeur et la vie de freelance par Nicolas Martignole</description>
	<lastBuildDate>Wed, 08 Feb 2012 11:54:37 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Traitement du XML en Groovy</title>
		<link>http://www.touilleur-express.fr/2010/02/14/traitement-du-xml-en-groovy/</link>
		<comments>http://www.touilleur-express.fr/2010/02/14/traitement-du-xml-en-groovy/#comments</comments>
		<pubDate>Sun, 14 Feb 2010 15:55:40 +0000</pubDate>
		<dc:creator>Nicolas Martignole</dc:creator>
				<category><![CDATA[groovy]]></category>
		<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://www.touilleur-express.fr/?p=3165</guid>
		<description><![CDATA[
Groovy est un langage particulièrement adapté lorsqu&#8217;il s&#8217;agit de traiter des fichiers plats. Pour rédiger le 500ème billet du blog, j&#8217;ai exporté au format WXR (WordPress eXtended RSS) l&#8217;ensemble des billets. Cela donne un gros fichier XML de 75 762 lignes que vous pouvez télécharger ici.
Lire un fichier XML avec Groovy
Pour ouvrir et lire un fichier XML avec Groovy, rien de plus simple. Il existe 2 classes principales : XmlSlurper et XmlParser. Aujourd&#8217;hui nous ne verrons que le premier.
La structure du fichier XML utilise le format WXR (WordPress eXtended RSS ...]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.touilleur-express.fr/wp-content/tag_groovy_150_150.jpg"><img src="http://www.touilleur-express.fr/wp-content/tag_groovy_150_150.jpg" alt="" title="tag_groovy_150_150" width="150" height="150" class="alignnone size-full wp-image-2944" /></a><br />
Groovy est un langage particulièrement adapté lorsqu&#8217;il s&#8217;agit de traiter des fichiers plats. Pour rédiger le 500ème billet du blog, j&#8217;ai exporté au format WXR (WordPress eXtended RSS) l&#8217;ensemble des billets. Cela donne un gros fichier XML de 75 762 lignes que vous pouvez télécharger <a href="http://www.touilleur-express.fr/code/backup_touilleur_express.xml.gz">ici</a>.</p>
<h3>Lire un fichier XML avec Groovy</h3>
<p>Pour ouvrir et lire un fichier XML avec Groovy, rien de plus simple. Il existe 2 classes principales : XmlSlurper et XmlParser. Aujourd&#8217;hui nous ne verrons que le premier.<br />
La structure du fichier XML utilise le format WXR (WordPress eXtended RSS format). J&#8217;ai dû adapter et corriger quelques coquilles pour que le fichier puisse être parsé correctement.</p>
<p>Voyons tout d&#8217;abord comment lire un fichier XML en Groovy :</p>
<pre class="brush:groovy">
def file = new File("wordpress.2010-02-14.xml")
def root=new XmlSlurper().parse(file)
</pre>
<p>Plutôt simple non ?</p>
<p>Si nous prenons cette structure XML par exemple :</p>
<pre class="brush:xml">
&lt;rss version="2.0"
	xmlns:excerpt="http://wordpress.org/export/1.0/excerpt/"
	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:wp="http://wordpress.org/export/1.0/"
&gt;

&lt;channel&gt;
	&lt;title&gt;Le Touilleur Express&lt;/title&gt;
        ...
        &lt;item&gt;
            // un article
        &lt;/item&gt;
        &lt;item&gt;
            // un article
        &lt;/item&gt;
&lt;/channel&gt;
&lt;/rss&gt;
</pre>
<p>L&#8217;accès à un attribut est très simple en Groovy. Voici comment afficher le titre du blog et comment afficher le nombre d&#8217;items de la balise channel:</p>
<pre class="brush:groovy">
def file = new File("wordpress.2010-02-14.xml")
def root=new XmlSlurper().parse(file)

println "Blog title : "+root.channel['title']

println "Number of RSS items : "+root.channel.item.size()
</pre>
<pre>
nicolas@localhosr> groovy readXml.groovy
Blog title : Le Touilleur Express
Number of RSS items : 805
</pre>
<h3>Itérer des noeuds</h3>
<p>L&#8217;itération des noeuds XML s&#8217;effectue à l&#8217;aide de closure. La structure RSS de l&#8217;ensemble des articles est construite autour du noeud &laquo;&nbsp;item&nbsp;&raquo;. WordPress y ajoute un ensemble d&#8217;attributs, ce qui permet de distinguer les articles publiés des brouillons, de distinguer les images téléchargées des pages, etc.</p>
<p>Prenons cet exemple de code :</p>
<pre class="brush:groovy">
def file = new File("wordpress.2010-02-14.xml")
def root=new XmlSlurper().parse(file)

root.channel.item.each{it->
	if(it.post_type.text().equals("post")){
		if(it.status.text().equals("publish")){
			println (it.title.text(),"UTF-8")
		}
	}
}
</pre>
<p>L&#8217;élément CHANNEL est constitué d&#8217;une collection d&#8217;ITEM. Pour chacun de ces ITEMs je récupere la valeur de l&#8217;attribut TITLE. Enfin l&#8217;accesseur text() permet de récupérer le titre de l&#8217;article du Touilleur Express.<br />
Le format d&#8217;entrée est UTF-8. Lors de l&#8217;exécution sur Mac, l&#8217;encoding de la plateforme étant par défaut MacRoman, les caractères accentués entre autre ne sont pas correctement affichés. Nous verrons tout à l&#8217;heure comment spécifier le format de sortie.</p>
<h3>Générer un nouveau fichier au format HTML</h3>
<p>Maintenant que vous savez lire un fichier XML, itérer des noeuds, pouvez-vous m&#8217;écrire quelques lignes pour générer une page HTML avec la liste des articles, un lien vers l&#8217;article et la date de publication ?</p>
<p>Voici le fichier d&#8217;entrée :</p>
<pre class="brush:xml">
&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;rss version="2.0"
	xmlns:excerpt="http://wordpress.org/export/1.0/excerpt/"
	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:wp="http://wordpress.org/export/1.0/"
&gt;

&lt;channel&gt;
	&lt;title&gt;Le Touilleur Express&lt;/title&gt;
		&lt;item&gt;
			&lt;title&gt;Article classique&lt;/title&gt;
			&lt;wp:post_type&gt;post&lt;/wp:post_type&gt;
			&lt;wp:status&gt;publish&lt;/wp:status&gt;
			&lt;link&gt;http://www.touilleur-express.fr/2003/11/22/pourquoi-java-sappelle-java/&lt;/link&gt;
			&lt;pubDate&gt;Sat, 22 Nov 2003 09:28:40 +0000&lt;/pubDate&gt;
		&lt;/item&gt;
		&lt;item&gt;
			&lt;title&gt;Article de brouillon&lt;/title&gt;
			&lt;wp:post_type&gt;post&lt;/wp:post_type&gt;
			&lt;wp:status&gt;draft&lt;/wp:status&gt;
			&lt;link&gt;http://www.touilleur-express.fr/&lt;/link&gt;
			&lt;pubDate&gt;Sat, 22 Nov 2003 09:28:40 +0000&lt;/pubDate&gt;
		&lt;/item&gt;
		&lt;item&gt;
			&lt;title&gt;Page wordpress&lt;/title&gt;
			&lt;wp:post_type&gt;page&lt;/wp:post_type&gt;
			&lt;wp:status&gt;publish&lt;/wp:status&gt;
			&lt;link&gt;http://www.touilleur-express.fr/&lt;/link&gt;
			&lt;pubDate&gt;Sat, 22 Nov 2003 09:28:40 +0000&lt;/pubDate&gt;
		&lt;/item&gt;
	&lt;/channel&gt;
&lt;/rss&gt;
</pre>
<p>Votre script Groovy doit parser le fichier XML ci-dessus, et générer ce fichier HTML :</p>
<pre class="brush:html">
&lt;html&gt;
&lt;head&gt;
&lt;title&gt;Le Touilleur Express articles&lt;/title&gt;
&lt;meta http-equiv='Content-Type' content='text/html; charset=UTF-8'/&gt;

&lt;body&gt;
&lt;a href='http://www.touilleur-express.fr/2003/11/22/pourquoi-java-sappelle-java/' target='new'&gt;Article classique&lt;/a&gt; publi&eacute; le Sat, 22 Nov 2003 09:28:40 +0000&lt;br/&gt;

&lt;/body&gt;
&lt;/html&gt;
</pre>
<p>Allez au boulot, à vous de travailler. Je vous posterai la réponse un peu plus tard.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.touilleur-express.fr/2010/02/14/traitement-du-xml-en-groovy/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Version Play! de l&#039;application ZenContact de Zenika</title>
		<link>http://www.touilleur-express.fr/2010/02/12/version-play-de-lapplication-zencontact-de-zenika/</link>
		<comments>http://www.touilleur-express.fr/2010/02/12/version-play-de-lapplication-zencontact-de-zenika/#comments</comments>
		<pubDate>Fri, 12 Feb 2010 15:55:19 +0000</pubDate>
		<dc:creator>Nicolas Martignole</dc:creator>
				<category><![CDATA[groovy]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[play]]></category>

		<guid isPermaLink="false">http://www.touilleur-express.fr/?p=3111</guid>
		<description><![CDATA[Après avoir codé la version Grails de l&#8217;application Zencontact de Zenika, voyons aujourd&#8217;hui la version développée avec le framework Play! grâce à Guillaume Bort, créateur de Play!
Mais avant, quelques mots sur Play!, un framework qui gagne à être connu.
Présentation du framework Play!
Play! est un framework Web Java open source (license Apache 2.0) développé par Guillaume Bort et une équipe de contributeurs. Play! a été écrit par des développeurs Webs, pour des développeurs Webs. Attention, je ne parle pas de développeur Web au sens css/html/php mais bien de vous, développeur Java, ...]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.touilleur-express.fr/wp-content/tag150150_play.jpg"><img src="http://www.touilleur-express.fr/wp-content/tag150150_play.jpg" alt="" title="tag150150_play" width="150" height="150" class="alignleft size-full wp-image-2672" /></a>Après avoir codé <a href="http://www.touilleur-express.fr/2009/12/20/grails-lapplication-zencontact-de-zenika/">la version Grails</a> de l&#8217;application <a href="http://blog.zenika.com/index.php?post/2009/03/10/Concours-Développer-une-application-web-en-Wicket3 ">Zencontact de Zenika,</a> voyons aujourd&#8217;hui la version développée avec le framework Play! grâce à <strong>Guillaume Bort</strong>, créateur de Play!<br />
Mais avant, quelques mots sur Play!, un framework qui gagne à être connu.</p>
<p><strong>Présentation du framework Play!</strong><br />
Play! est un framework Web Java open source (<a href="http://www.apache.org/licenses/LICENSE-2.0.html">license Apache 2.0</a>) développé par Guillaume Bort et une équipe de contributeurs. Play! a été écrit par des développeurs Webs, pour des développeurs Webs. Attention, je ne parle pas de développeur Web au sens css/html/php mais bien de vous, développeur Java, qui à un moment donné de votre vie avait dû coder cette @#$* de page en JSP ou en JSF.</p>
<p>Quelques caractéristiques de Play! :<br />
- En mode développement, il suffit d&#8217;éditer un fichier Java, de le sauvegardez et rechargez votre navigateur pour tester. Il n&#8217;y a pas de compilations de votre code Java ! Il n&#8217;est pas nécessaire de relancer le serveur. Cela fonctionne pour les pages comme pour les classes Java, ce qui est très pratique et très productif. Votre IDE assure même une première vérification, comme avec IDEA IntelliJ, ce qui permet de travailler plus facilement qu&#8217;avec Grails à mon avis.<br />
- Play est un framework sans état où la vue présentée au navigateur client n&#8217;est pas la représentation d&#8217;un état sur le serveur, contrairement à d&#8217;autres frameworks webs, ce qui permet de monter en charge sans risques. Cela respecte au passage l&#8217;architecture web, qui est sans état par nature.<br />
- Les pages webs utilisent un système de templates simples basés sur Groovy comme Expression Language. Il est possible de faire de l&#8217;héritage de pages, des inclusions et de définir des tags comme avec Grails.<br />
- Lorsqu&#8217;une erreur survient, Play s&#8217;efforce de présenter la source de l&#8217;erreur en vous montrant le code plutôt qu&#8217;une StackTrace assez indigeste.<br />
- Play est intégré avec Hibernate, OpenID, Memcached.<br />
- Un système de modules similaire aux plugins de Grails est en cours de construction.<br />
- Play n&#8217;est pas un framework de prototypage, c&#8217;est un outil mis en production avec de solides références<br />
- Play contrairement à Grails (que j&#8217;adore aussi) est complètement basé sur Java, ce qui permet de garder ses réflexes de &laquo;&nbsp;java-istes&nbsp;&raquo;, son IDE favori (IDEA IntelliJ) et donc de travailler sans changer ses habitudes<br />
- Play démarre très rapidement en mode développement, bien plus vite que Grails<br />
- Enfin c&#8217;est fait par des Français, alors Cocorico, on va tester cela rapidement</p>
<p><strong>Démonstration de l&#8217;application finale</strong><br />
<object width="560" height="340"><param name="movie" value="http://www.youtube.com/v/WLEJaLh6rR8&#038;hl=fr_FR&#038;fs=1&#038;"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/WLEJaLh6rR8&#038;hl=fr_FR&#038;fs=1&#038;" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="560" height="340"></embed></object></p>
<p><strong>Fonctions implémentées</strong><br />
Pour reprendre la liste des fonctions initiales, voici le périmètre couvert par la version Play!<br />
* La navigation entre pages<br />
* L’organisation d’une structure commune des pages (Type Tiles / Sitemesh)<br />
* La désactivation du lien correspondant à la page courante<br />
* L’édition d’un contact<br />
* La création d’un contact<br />
* Lister les contacts<br />
* L’ajout rapide d’un contact dans une liste<br />
* Le refresh de la date courante via appels Ajax<br />
* L’édition « in place » d’un libellé sans passer par un écran d’édition<br />
* L’ajout de la validation (Nom et prénom obligatoires, contrôle du format date, contrôle du type email)<br />
* Utilisation d’un date picker<br />
* Synchronisation du format du DatePicker avec le format utilisé par le convertisseur<br />
* Gestion de la problématique du refresh afin d’éviter la double soumission<br />
* L’affichage de message d’erreurs</p>
<p>Les fonctions non implémentées:<br />
-  le tri des colonnes n&#8217;est pas implémenté (order et orderBy). Play est tout à fait capable de le faire, le module CRUD par exemple a une méthode list avec un order et un orderBy. Cependant ce code est assez verbeux.</p>
<p>3 autres points <strong>non</strong> couvert par la version Play :<br />
* Ajout des mêmes contrôles de validation côté client, en Javascript<br />
* Non duplication du code du formulaire… le même composant doit être utilisé pour la page d’édition de contacts et de liste des contacts<br />
* La réutilisation des mêmes messages d’erreurs en validation serveur et javascript</p>
<p>L&#8217;application utilise une base de données en mémoire, tout comme la version Grails. Une entité Contact est géré par un unique contrôleur. Au premier coup d&#8217;oeil, j&#8217;apprecie de retrouver ce mode de convention au lieu de la configuration, comme pour Grails.</p>
<p>Je ne pourrai pas comparer le nombre de lignes de codes, étant donné que la version Play! n&#8217;utilise pas le module CRUD. Mais la class Application ne fait que 30 lignes de code effectif pour remplir le cahier des charges exact de Zenika, le tout avec de la persistance. La class <a href="http://bazaar.launchpad.net/%7Eplay-developers/play/1.0/annotate/head%3A/modules/crud/app/controllers/CRUD.java">CRUD.java</a> du module CRUD de Play! est assez verbeuse, mais très pratique.</p>
<p><strong>L&#8217;entité de départ</strong><br />
<a href="http://www.nofluffjuststuff.com/home/main">&laquo;&nbsp;No fluff, just stuff&nbsp;&raquo;</a>  décrit bien la simplicité de la classe Contact. Ecrite en Java, elle étend une classe de base de Play! tout en restant très simple :</p>
<pre class="brush:java">
// (manque les imports

@Entity
public class Contact extends Model {
    @Required
    public String firstname;

    @Required
    public String name;

    @Required
    public Date birthdate;

    @Required
    @Email
    public String email;
}
</pre>
<p>L&#8217;annotation @play.data.validation.Required de Play permet de rendre obligatoire ce paramètre dans la vue, tout comme le tag @Email.<br />
Pour comparer, voici la version Grails de Contact:</p>
<pre class="brush:groovy">
package org.letouilleur.demo

class Contact {
	String nom
	String prenom
	Date dateNaissance
	String email

	static constraints={
		prenom(blank:false)
		nom(blank:false)
		dateNaissance(nullable:true)
		email(email:true,nullable:true,blank:true,unique:true)
	}
}
</pre>
<p><strong>Le Controller Application</strong><br />
Le Controller principal retourne la date et l&#8217;heure courante pour la page d&#8217;accueil. La méthode list() retourne une liste des Contacts, sans prendre en compte cependant deux critères de la vue (order et orderBy). La méthod form() est similaire à la méthode show() de la version Grails,</p>
<pre class="brush:java">

public class Application extends Controller {

    public static void index() {
        Date now = new Date();
        render(now);
    }

    public static void list() {
        List<contact> contacts = Contact.find("order by name, firstname").fetch();
        render(contacts);
    }

    public static void form(Long id) {
        if (id == null) {
            render();
        }
        Contact contact = Contact.findById(id);
        render(contact);
    }

    public static void save(@Valid Contact contact) {
        if (validation.hasErrors()) {
            if (request.isAjax()) error("Invalid value");
            render("@form", contact);
        }
        contact.save();
        list();
    }
}
</contact></pre>
<p>Notez tout d&#8217;abord que dans la version Play, les méthodes du Controller ne retourne pas de Model, mais délèguent à un render l&#8217;opération de restitution du modèle. J&#8217;apprécie la légèreté et la simplicité du code, qui est facilement lisible. Certains d&#8217;entre vous doivent être entrain de se demander pourquoi le Controller étend une classe de base, et même penser que c&#8217;est une limitation&#8230; ce que je ne partage pas. Cela ne me dérange pas ici de restreindre cette classe Java à un rôle, en utilisant l&#8217;héritage pour la typer. Il y a plusieurs exemples intéressants dans Play! où l&#8217;approche est moins académique, et franchement, moi j&#8217;aime bien.<br />
Tenez, prenons la classe Contact. Avez-vous noté que les attributs sont publiques ? Qu&#8217;il n&#8217;y a pas d&#8217;encapsulation ? A priori, pour récupérer des champs simples, pourquoi  s&#8217;embêter à les rendre private, pour ajouter un couple getter/setter simple ? A  noter que si vous souhaitez écrire une méthode getName, cela reste possible.</p>
<pre class="brush:java">
public class Contact extends Model {
    @Required
    public String name;

    /** Met en majuscule le nom de famille */
    public String getName() {
        return (name!=null ? name.toUpperCase() : null);
    }

}
</pre>
<p>L&#8217;application est composée de 2 fichiers Java et de 3 pages HTML, ce qui est vraiment très léger. Bonne nouvelle : je n&#8217;ai pas croisé de fichiers XML pour faire marcher le tout. Là où j&#8217;ai eu quelques soucis pour comprendre, c&#8217;est la partie vue. Je vous donne un avis personnel : j&#8217;ai plus de mal avec la syntaxe de Play qu&#8217;avec celle de Grails pour les pages. Mais bon, c&#8217;est une histoire d&#8217;habitude je pense. Développons un peu cet argument.</p>
<p>Voici la version Play de la page d&#8217;accueil. Comme dans Grails qui utilise Sitemesh, il est très facile de définir un template de page générique :</p>
<pre class="brush:html">

&lt;!DOCTYPE html&gt;
&lt;html&gt;
    &lt;head&gt;
    	&lt;title&gt;Zencontact, by zenexity  ★ #{get 'title' /}&lt;/title&gt;
    	&lt;meta http-equiv="Content-Type" content="text/html; charset=utf-8"/&gt;
        &lt;link rel="stylesheet" type="text/css" media="screen" href="@{'public/stylesheets/style.css'}" /&gt;
        &lt;link rel="stylesheet" type="text/css" media="screen" href="@{'public/stylesheets/south-street/jquery-ui-1.7.2.custom.css'}" /&gt;
    	&lt;script src="@{'public/javascripts/jquery-1.4.min.js'}" type="text/javascript" charset="utf-8"&gt;&lt;/script&gt;
    	&lt;script src="@{'public/javascripts/jquery-ui-1.7.2.custom.min.js'}" type="text/javascript" charset="utf-8"&gt;&lt;/script&gt;
    	&lt;script src="@{'public/javascripts/jquery.editinplace.packed.js'}" type="text/javascript" charset="utf-8"&gt;&lt;/script&gt;
    &lt;/head&gt;
	&lt;body&gt;
	    &lt;div id="zencontact"&gt;
    		&lt;header&gt;
    			&lt;img src="@{'public/images/logo.png'}" alt="logo" id="logo" /&gt;
    			&lt;h1&gt;Zencontact &lt;span&gt;by zenexity&lt;/span&gt;&lt;/h1&gt;
    		&lt;/header&gt;
    		&lt;nav&gt;
    			&lt;a id="home" href="@{index()}" class="${request.action =~ /index/ ? 'selected' : ''}"&gt;Home&lt;/a&gt;
    			&lt;a id="list" href="@{list()}" class="${request.action =~ /list/ ? 'selected' : ''}"&gt;List&lt;/a&gt;
    			&lt;a id="new" href="@{form()}" class="${request.action =~ /form|save/ ? 'selected' : ''}"&gt;New&lt;/a&gt;
    		&lt;/nav&gt;
    		&lt;section&gt;
    		    #{doLayout /}
    		&lt;/section&gt;
    		&lt;footer&gt;
    			&lt;a href="http://www.w3.org/TR/html5/"&gt;html5&lt;/a&gt; -
    			&lt;a href="http://www.w3.org/TR/css3-roadmap/"&gt;css3&lt;/a&gt; -
    			&lt;a href="http://www.playframework.org/"&gt;playframework&lt;/a&gt;
    		&lt;/footer&gt;
		&lt;/div&gt;
	&lt;/body&gt;
&lt;/html&gt;
</pre>
<p>La ligne 24 sera remplacée par le contenu des pages filles. La page d&#8217;accueil avec le compteur de temps étend la page main.html, définit le titre puis utilise jQuery pour récupérer l&#8217;heure. Ma version Grails était moins verbeuse car j&#8217;ai utilisé un GTag, ce qui a l&#8217;avantage d&#8217;alléger le code de cette page, mais ce qui n&#8217;est pas très réaliste pour un projet. Guillaume a prit l&#8217;option d&#8217;implémenter ici directement la logique et l&#8217;affichage, pourquoi pas ?</p>
<pre class="brush:html">
#{extends 'main.html' /}
#{set title:'Home' /}
<p id="time">
    <span>${now.format("EEEE',' MMMM dd',' yyyy")}</span>${now.format("hh'h' MM'mn' ss's'")}


<script type="text/javascript" charset="utf-8">
    setInterval(function() {
        $('section').load('@{index()} #time')
    }, 1000)
</script>
</pre>
<p>La page list.html est chargée d&#8217;itérer la collection des Contacts et de les afficher dans un tableau. Play a <a href="http://www.playframework.org/documentation/1.0.1/guide6">un système de tag</a> comme Grails, ce qui permet par exemple d&#8217;utiliser le tag <em>list</em> pour itérer une collection:</p>
<pre class="brush:java">
&lt;ul&gt;
#{list items:products, as:'product'}
    &lt;li&gt;${product}&lt;/li&gt;
#{/list}
&lt;/ul&gt;
</pre>
<p>La page list.html est donc simple. J&#8217;ai essayé sans succès de coder des liens sur les entêtes de colonnes afin d&#8217;effectuer un tri en passant un orderBy et un order, mais fautes de temps, je n&#8217;ai pas réussi à améliorer la version de Guillaume Bort.</p>
<pre class="brush:html">
#{extends 'main.html' /}
#{set title:'List' /}

&lt;table&gt;
	&lt;thead&gt;
		&lt;tr&gt;
			&lt;th class="name"&gt;Name&lt;/th&gt;
			&lt;th class="firstname"&gt;First name&lt;/th&gt;
			&lt;th class="birthdate"&gt;Birth date&lt;/th&gt;
			&lt;th class="email"&gt;Email&lt;/th&gt;
			&lt;th class="edit"&gt;&lt;/th&gt;
		&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
	    #{list contacts, as:'contact'}
	    &lt;tr class="contact" contactId="${contact.id}" draggable="true"&gt;
   			&lt;td id="name-${contact.id}"&gt;${contact.name}&lt;/td&gt;
   			&lt;td id="firstname-${contact.id}"&gt;${contact.firstname}&lt;/td&gt;
   			&lt;td id="birthdate-${contact.id}"&gt;${contact.birthdate?.format('yyyy-MM-dd')}&lt;/td&gt;
   			&lt;td id="email-${contact.id}"&gt;${contact.email}&lt;/td&gt;
   			&lt;td&gt;&lt;a href="@{form(contact.id)}"&gt;&gt;&lt;/a&gt;&lt;/td&gt;
   		&lt;/tr&gt;
	    #{/list}
	    &lt;tr&gt;
	        #{form @save()}
	        &lt;td&gt;&lt;input type="text" name="contact.name"&gt;&lt;/td&gt;
	        &lt;td&gt;&lt;input type="text" name="contact.firstname"&gt;&lt;/td&gt;
	        &lt;td&gt;&lt;input type="text" name="contact.birthdate"&gt;&lt;/td&gt;
	        &lt;td&gt;&lt;input type="text" name="contact.email"&gt;&lt;/td&gt;
	        &lt;td&gt;&lt;input type="submit" value="+"&gt;&lt;/td&gt;
	        #{/form}
	    &lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
// note : code Javascript pour l'Edit-In-Place et le Drag-and-drop effacé.
</pre>
<p>La page permet de lister une collection, d&#8217;éditer directement dans le tableau le nom d&#8217;une personne, et d&#8217;appeler la page form.html pour éditer une fiche. Notez dans la démonstration que la version de Guillaume affiche un nom en Chinois sans problèmes, merci l&#8217;UTF-8.</p>
<p>Enfin la dernière page est le formulaire de création et d&#8217;édition d&#8217;une fiche.</p>
<pre class="brush:html">
#{extends 'main.html' /}
#{set title:'Form' /}

#{form @save()}
&lt;input type="hidden" name="contact.id" value="${contact?.id}"&gt;

&lt;p class="field"&gt;
    &lt;label for="name"&gt;Name:&lt;/label&gt;
    &lt;input type="text" id="name" name="contact.name" value="${contact?.name}"&gt;
    &lt;span class="error"&gt;${errors.forKey('contact.name')}&lt;/span&gt;
&lt;/p&gt;

&lt;p class="field"&gt;
    &lt;label for="firstname"&gt;First name:&lt;/label&gt;
    &lt;input type="text" id="firstname" name="contact.firstname" value="${contact?.firstname}"&gt;
    &lt;span class="error"&gt;${errors.forKey('contact.firstname')}&lt;/span&gt;
&lt;/p&gt;

&lt;p class="field"&gt;
    &lt;label for="birthdate"&gt;Birth date:&lt;/label&gt;
    &lt;input type="text" id="birthdate" name="contact.birthdate" value="${contact?.birthdate?.format('yyyy-MM-dd')}"&gt;
    &lt;span class="error"&gt;${errors.forKey('contact.birthdate')}&lt;/span&gt;
&lt;/p&gt;

&lt;p class="field"&gt;
    &lt;label for="email"&gt;Email:&lt;/label&gt;
    &lt;input type="text" id="email" name="contact.email" value="${contact?.email}"&gt;
    &lt;span class="error"&gt;${errors.forKey('contact.email')}&lt;/span&gt;
&lt;/p&gt;

&lt;p class="buttons"&gt;
    &lt;a href="@{list()}"&gt;Cancel&lt;/a&gt; or &lt;input type="submit" value="Save this contact" id="saveContact"&gt;
&lt;/p&gt;

&lt;script type="text/javascript" charset="utf-8"&gt;
    $("#birthdate").datepicker({dateFormat:'yy-mm-dd', showAnim:'fadeIn'})
&lt;/script&gt;
#{/form}
</pre>
<p>Par rapport à la version Grails, le format de la Date est bien mieux géré. J&#8217;aime bien aussi l&#8217;utilisation de Groovy, ce qui permet de retrouver les astuces et de gagner du temps, comme lorsque l&#8217;on s&#8217;assure qu&#8217;un paramètre n&#8217;est pas null avant de l&#8217;appeler :</p>
<pre class="brush:html">
 &lt;input type="text" id="birthdate" name="contact.birthdate" value="${contact?.birthdate?.format('yyyy-MM-dd')}"&gt;
</pre>
<p><strong>Bootstrap</strong><br />
Play permet de définir des entrées d&#8217;exemple dans un fichier externe, afin de remplir la base de tests au démarrage. Le format <a href="http://www.yaml.org/spec/1.2/spec.html">YAML</a> est très simple à lire, et il est supporté &lt;TROLL&gt;par le meilleur éditeur du monde : <a href="http://www.jetbrains.com">IDEA IntelliJ</a> &lt;/TROLL&gt; maintenant aussi disponible en version open-source.</p>
<pre class="brush:shell">
Contact(warry):
    name:       Dantec
    firstname:  Maxime
    birthdate:  1985-11-12
    email:      hello-xxx@warry.fr

Contact(guillaume):
    name:       Bort
    firstname:  Guillaume
    birthdate:  1980-12-21
    email:      xxx-bob@gmail.com

Contact(たの):
    name:       鈴木
    firstname:  太郎
    birthdate:  1970-05-13
    email:      contact@xxxjapan.com
</pre>
<p>La classe Bootstrap.java de Play permet de charger les Contacts, si la liste en base est vide :</p>
<pre class="brush:java">

@OnApplicationStart
public class Bootstrap extends Job {
    public void doJob() {
        if(Contact.count() == 0) {
            Fixtures.load("data.yml");
        }
    }
}
</pre>
<p><strong>Le résultat final</strong><br />
Le résultat final est très léger, et franchement, en terme de performances, le démarrage est moins poussif que Grails. La possibilité de débugger avec son éditeur, et le fait d&#8217;avoir des Stacktraces propres est aussi un gain par rapport à Grails. Je n&#8217;ai pas eu à relancer le serveur, en fait vous n&#8217;avez même pas besoin de compiler vos classes Java. Sur IDEA IntelliJ il n&#8217;y a pas de compilation comme dans Eclipse lorsque vous sauvez vos fichiers. En fait, vous ne sauvez jamais vos fichiers avec IDEA IntelliJ. Celui-ci le fait lorsque vous perdez le focus sur la fenêtre principal. Du coup, le couple IDEA + Play déchire en terme de vitesse de développement.</p>
<p>J&#8217;ai cependant pas mal de bémols, très suggestifs et que vous ne devez pas prendre pour argent comptant. Tout d&#8217;abord du côté de la vue, j&#8217;ai tellement l&#8217;habitude des syntaxes verbeuses, à la JSF ou à la GSP pour Grails, que j&#8217;ai eu un peu de mal à me faire à la syntaxe de Play. Par ailleurs, parfois certains tags ne sont pas très constistants entre eux, et il n&#8217;est pas très évident de rentrer facilement dans cette partie.</p>
<p>Un point positif de Play c&#8217;est la possibilité d&#8217;utiliser Selenium afin d&#8217;ajouter des tests d&#8217;intégrations très facilement. Il suffit de lancer l&#8217;application en mode test avec &laquo;&nbsp;play test zencontact&nbsp;&raquo; et ensuite d&#8217;ouvrir la page http://localhost:9000/@tests pour pouvoir lancer les tests Selenium. C&#8217;est une idée qui va encourager l&#8217;utilisation de TDD pour écrire une application Play, ce qui est vraiment bien.</p>
<p>Concernant un point sur lequel j&#8217;ai eu des soucis avec Grails, c&#8217;est le support des bases &laquo;&nbsp;Legacy&nbsp;&raquo;. Florent Ramière de <a href="http://www.jaxio.com">Jaxio</a> avec qui j&#8217;ai travaillé il y a une semaine, m&#8217;a montré les limitations de Grails dès qu&#8217;il s&#8217;agit de prendre une base existante. Oui cela fonctionne, c&#8217;est jouable, mais Grails perd de son charme lorsqu&#8217;il faut jouer à l&#8217;équilibriste avec des tables existantes. Je pense que Play! sera peut-être plus à l&#8217;aise grâce à l&#8217;intégration de JPA, mais nous devrions refaire le test sur la base de données de démarrage de <a href="http://www.jaxio.com/">Celerio</a> pour voir le tout sur un cas d&#8217;entreprise.</p>
<p><strong>Conclusion</strong><br />
Ce qui m&#8217;a séduit dans le code, c&#8217;est cette simplicité et ces idées novatrices qui sont proches de Grails et de Rails, mais le tout en Java. Avant tout pensé par des développeurs Webs, ce que je suis sans aucuns doutes, je trouve qu&#8217;il serait intéressant pour vous d&#8217;y jeter un oeil, et d&#8217;apprendre à vous en servir. Par rapport à Grails, je ne sais pas si la notion de Service et d&#8217;injection existe par exemple. Par contre, un moteur de Jobs permet d&#8217;exécuter périodiquement des actions, sans besoin d&#8217;avoir une requête HTTP.<br />
Des modules de sécurité, d&#8217;authentification, le support de GWT et de Spring, il y a de quoi démarrer une application Web rapidement. J&#8217;ai quelques réserves sur la partie vue, mais je pense que c&#8217;est par manque d&#8217;expérience.<br />
Je ne sais pas non plus si Play a la notion de Render pour afficher la liste des Contacts au format XML ou JSON très simplement, ou s&#8217;il faut passer par une API externe supplémentaire. Enfin on apprécie vraiment le fait de ne même pas devoir compiler son code Java. Vous pouvez dire adieu à Maven/Ant et même JRebel, là on parle de productivité.<br />
La mise en production est simple, Guillaume m&#8217;a confirmé qu&#8217;il est facile de créer un WAR final pour le déployer comme avec Grails:</p>
<pre>
play war zencontact -o zencontact.war
</pre>
<p>Play! par rapport à Grails manque de modules, mais ce n&#8217;est qu&#8217;une histoire de temps. Le code est propre, la documentation plutôt bien écrite, et l&#8217;ensemble est codé sur de solides fondations, basées sur une expérience et un certain talent pour écrire cela de manière moderne. J&#8217;ai apprécié, et je le range en plus sur mon étagère de framework à connaître pour travailler efficacement.</p>
<p>Le code complet de l&#8217;application zencontact est disponible ici.</p>
<p>1. Téléchargez <a href="http://download.playframework.org/1.0-nightly/play-1.0-r844.zip">une version récente de Play<br />
</a><br />
2. Décompressez dans un répertoire, ajoutez à votre PATH ce répertoire<br />
3. Ouvrez un terminal, vérifiez que Play démarre en tapant &laquo;&nbsp;play&nbsp;&raquo;<br />
4. Téléchargez <a href="http://guillaume.bort.fr/apps/zencontact-play.zip">l&#8217;application zencontact</a><br />
5. Décompressez-là dans un autre répertoire comme C:\demo pour avoir au final un C:\demo\zencontact par exemple<br />
6. Dans le répertoire C:\demo, tapez &laquo;&nbsp;play run zencontact&nbsp;&raquo; et ouvrez votre navigateur sur http://localhost:9000</p>
<p>Merci à Guillaume Bort de Zenexity qui a codé la version Play de l&#8217;application. Guillaume travaille pour <a href="http://www.zenexity.fr/">Zenexity</a>, un cabinet de conseils et d&#8217;architecture qui propose une démarche d&#8217;architecture autour du Web. Allez voir aussi leurs différents billets car il y a beaucoup d&#8217;idées intéressantes et novatrices. Enfin ils organisent <a href="http://www.zenexity.fr/seminaires/developper-avec-play/">des formations sur Play</a>, ce qui pourra intéresser les équipes en phase de démarrage.</p>
<p>Allez Grails, fait pas la tête, t&#8217;es encore mon préféré, mais tu as un sérieux concurrent !</p>
<p>A bientôt.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.touilleur-express.fr/2010/02/12/version-play-de-lapplication-zencontact-de-zenika/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
	</channel>
</rss>

