<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:blogger="http://schemas.google.com/blogger/2008" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;DUMDQX08eCp7ImA9WhBbF0o.&quot;"><id>tag:blogger.com,1999:blog-1231386620637429487</id><updated>2013-05-17T09:57:50.370+02:00</updated><category term="AOP" /><category term="Mockito" /><category term="Play 2.0" /><category term="JPA" /><category term="GWT" /><category term="magazine" /><category term="planetplay" /><category term="Lucene" /><category term="JUG" /><category term="Objectify" /><category term="QueryDSL" /><category term="UiBinder" /><category term="GWT Designer" /><category term="Realtime" /><category term="Musique" /><category term="Hibernate" /><category term="Mongo" /><category term="Kotlin" /><category term="ROO" /><category term="JAX-RS" /><category term="APP Engine" /><category term="Hibernate Search" /><category term="ebook" /><category term="hadoop" /><category term="Swing" /><category term="Scalate" /><category term="EJB" /><category term="Scala" /><category term="Jetty" /><category term="Iteratee" /><category term="push" /><category term="Wicket" /><category term="spark" /><category term="Akka" /><category term="Grails" /><category term="DDD" /><category term="CDI" /><category term="Camel" /><category term="Spring" /><category term="Stateful" /><category term="Stateless" /><category term="JSON" /><category term="Comet" /><category term="Android" /><category term="Jersey" /><category term="Cloud" /><category term="HTML5" /><category term="Play" /><category term="Heroku" /><category term="Mobile" /><category term="NeoDatis" /><category term="JVM" /><category term="jQuery" /><category term="IDEA" /><category term="acteurs" /><category term="Java EE" /><category term="WebSocket" /><category term="Livres" /><category term="REST" /><category term="Slick" /><category term="Apprendre_Play" /><category term="Java FX" /><category term="NetBeans" /><category term="NoSQL" /><category term="Big Data" /><category term="hdfs" /><category term="Groovy" /><category term="Portlet" /><category term="iPhone" /><category term="programmez" /><category term="Maven" /><category term="HS" /><category term="BI" /><category term="Eclipse" /><category term="Jetbrains" /><category term="Agilité" /><category term="anorm" /><category term="Scalatra" /><category term="Glassfish" /><category term="shark" /><title type="text">CoffeeBean</title><subtitle type="html">Blog traitant des technologies Java</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://coffeebean.loicdescotte.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://coffeebean.loicdescotte.com/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/1231386620637429487/posts/default?start-index=26&amp;max-results=25&amp;redirect=false&amp;v=2" /><author><name>Loïc Descotte</name><uri>https://plus.google.com/117447657524839844765</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-vc8OSlrrAtM/AAAAAAAAAAI/AAAAAAAAFRA/sNj_WKeU-vI/s512-c/photo.jpg" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>114</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/blogspot/IUKF" /><feedburner:info uri="blogspot/iukf" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry gd:etag="W/&quot;DkEDQHg8eip7ImA9WhBbF0o.&quot;"><id>tag:blogger.com,1999:blog-1231386620637429487.post-7428084776691448701</id><published>2013-05-14T13:42:00.002+02:00</published><updated>2013-05-17T09:11:11.672+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2013-05-17T09:11:11.672+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Scala" /><category scheme="http://www.blogger.com/atom/ns#" term="hdfs" /><category scheme="http://www.blogger.com/atom/ns#" term="Big Data" /><category scheme="http://www.blogger.com/atom/ns#" term="Realtime" /><category scheme="http://www.blogger.com/atom/ns#" term="spark" /><category scheme="http://www.blogger.com/atom/ns#" term="shark" /><category scheme="http://www.blogger.com/atom/ns#" term="BI" /><category scheme="http://www.blogger.com/atom/ns#" term="hadoop" /><title>Calcul distribué avec Spark</title><content type="html">&lt;a href="http://spark-project.org/"&gt;Spark&lt;/a&gt; est un outil de calcul distribué, permettant de lancer de gros calcul sur un cluster.&lt;br /&gt;
&lt;br /&gt;
D'après ses développeurs, Spark est jusqu'à 100 fois plus rapide qu'Hadoop pour effectuer le même genre de taches.&lt;br /&gt;
Spark repose sur HDFS (Hadoop Distributed File System) mais les calculs se font en mémoire pour accélérer les traitements. Le but de cette accélération est de pouvoir effectuer des requêtes en temps réel sur de très gros volumes de données, par exemple sur les logs d'accès d'un site Internet. L'analyse des données en temps réel, le rêve quand on fait de la BI!&lt;br /&gt;
&lt;br /&gt;
D'autres applications sont possibles comme le machine learning ou le data mining. Mais commençons par mettre les mains dans le&amp;nbsp;cambouis!&lt;br /&gt;
Le coeur de Spark est écrit en Scala mais des API Java et Python sont également proposées pour interagir avec le framework.

Un shell est fourni par défaut, il permet de manipuler facilement l'API Scala de Spark. Très pratique pour faire des tests!&lt;br /&gt;
&lt;br /&gt;
Pour découvrir Spark, commençons par lire un fichier en local :
&lt;br /&gt;
&lt;pre class="java" name="code"&gt;val textFile = sc.textFile("README.md")
&lt;/pre&gt;
Note : sc est un objet disponible par défaut dans le shell, il correspond au contexte Spark courant.

&lt;br /&gt;
&lt;br /&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
On veut maintenant compter les occurences de chaque mot dans ce fichier :&lt;br /&gt;
&lt;pre class="java" name="code"&gt;val wordCounts = textFile.flatMap(line =&amp;gt; line.split(" ")) //on crée un tableau de mots
.map(word =&amp;gt; (word, 1)) // on crée un tuple par mot pour compter les occurrences
.reduceByKey((a, b) =&amp;gt; a + b) // on additionne les nombres d’occurrences en groupant par clé (par mot)
&lt;/pre&gt;
&lt;br /&gt;
Un aspect vraiment sympa et puissant avec Spark, il est possible de manipuler les fichiers locaux ou les fichiers distribués sur HDFS exactement de la même manière. L'API masque complètement cet aspect.

&lt;br /&gt;
On peut donc refaire la même chose mais en lisant le fichier sur HDFS comme ceci :

&lt;br /&gt;
&lt;pre class="java" name="code"&gt;val textFile = sc.textFile("hdfs://masterHost:9000/data/README.md")
&lt;/pre&gt;
&lt;br /&gt;
Modifions maintenant notre calcul, pour ne compter que les 9èmes mots de chaque ligne.
Si la ligne contient moins de 9 mots, on veut afficher "smaller than 9". 
Pour ça on peut appeler la fonction lift sur notre tableau de mot (fonction standard dans l'API Scala), qui nous renverra une Option[String].
&lt;br /&gt;
Le code devient alors :
&lt;br /&gt;
&lt;pre class="java" name="code"&gt;val wordNineCOunts = textFile.map(line =&amp;gt; line.split(" ")
.lift(9).getOrElse("smaller than 9")) // si la valeur n'est pas présente dans l'option, on écrit "smaller than 9"
.map(word =&amp;gt; (word, 1))
.reduceByKey((a, b) =&amp;gt; a + b)
&lt;/pre&gt;
&lt;br /&gt;
Pour afficher le résultat, on procède comme ceci : 

&lt;br /&gt;
&lt;pre class="java" name="code"&gt;wordNineCOunts.collect
&lt;/pre&gt;
On obtient alors : 
&lt;br /&gt;
&lt;pre class="xml" name="code"&gt;Array((different,1), (to,2), (other,1), (no,1), (params`.,1), (its,2), (spark:/,1), (open,1), (`/usr/local/lib/libmesos.so`,1), (of,1), (programming,1), (CPUs.,1), (HDFS,1), (smaller than 9,40), (want,1), (with,1), (so.,1), (the,1), (that,2), (minimum,,1), (Simple,1), (documentation,1), (bin,1), (their,1), (this,1), (variable,1))...
&lt;/pre&gt;
&lt;br /&gt;
Note : 'collect' permet de passer d'un objet Spark de type RDD (resilient distributed dataset) à un simple tableau de valeurs&lt;br /&gt;
&lt;br /&gt;
On peut aussi trier les résultats sur le deuxième membre de chaque tuple, c'est à dire trier les mots par nombre d’occurrence :
&lt;br /&gt;
&lt;pre class="java" name="code"&gt;wordNineCounts
.collect
.sortWith((a, b) =&amp;gt; a._2 &amp;gt; b._2)
&lt;/pre&gt;
&lt;pre class="xml" name="code"&gt;Array((smaller than 9,40), (to,2), (its,2), (that,2), (different,1), (other,1), (no,1), (params`.,1), (spark:/,1), (`/usr/local/lib/libmesos.so`,1), (of,1), (open,1), (programming,1), (CPUs.,1), (HDFS,1), (want,1), (with,1), (so.,1), (the,1), (minimum,,1), (Simple,1), (documentation,1), (bin,1), (their,1), (this,1), (variable,1))...
&lt;/pre&gt;
&lt;br /&gt;
En conculsion, Spark est un très bon cas d'utilisation de Scala, peu verbeux pour manipuler les données et bien adapté pour les traitements en parallèle, notamment grâce à l'&lt;a href="http://www.youtube.com/watch?v=3jg1AheF4n0"&gt;immutabilité poussée par le langage&lt;/a&gt;.
&lt;br /&gt;
Juste pour vous faire une idée, regardez ce que donnerait la même chose &lt;a href="http://spark-project.org/docs/latest/java-programming-guide.html"&gt;en Java&lt;/a&gt;.
&lt;br /&gt;
&lt;br /&gt;
Pour aller plus loin, vous pouvez aussi regarder Shark, qui repose sur Spark et apporte la possibilité de faire des requêtes avec un langage "SQL like" sur vos données distribuées. Shark est compatible avec &lt;a href="http://hive.apache.org/"&gt;Apache Hive&lt;/a&gt; tout en permettant de profiter de la vitesse d’exécution de Spark.&lt;img src="http://feeds.feedburner.com/~r/blogspot/IUKF/~4/2_HXnif9AVQ" height="1" width="1"/&gt;</content><link rel="replies" type="text/html" href="http://coffeebean.loicdescotte.com/2013/05/calcul-distribue-avec-spark.html#comment-form" title="0 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1231386620637429487/posts/default/7428084776691448701?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1231386620637429487/posts/default/7428084776691448701?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/IUKF/~3/2_HXnif9AVQ/calcul-distribue-avec-spark.html" title="Calcul distribué avec Spark" /><author><name>Loïc Descotte</name><uri>https://plus.google.com/117447657524839844765</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-vc8OSlrrAtM/AAAAAAAAAAI/AAAAAAAAFRA/sNj_WKeU-vI/s512-c/photo.jpg" /></author><thr:total>0</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://coffeebean.loicdescotte.com/2013/05/calcul-distribue-avec-spark.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEMNQX0-eyp7ImA9WhBXEUw.&quot;"><id>tag:blogger.com,1999:blog-1231386620637429487.post-7557827649947251231</id><published>2013-03-18T22:34:00.000+01:00</published><updated>2013-03-24T09:08:10.353+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2013-03-24T09:08:10.353+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Scala" /><category scheme="http://www.blogger.com/atom/ns#" term="Play" /><category scheme="http://www.blogger.com/atom/ns#" term="anorm" /><category scheme="http://www.blogger.com/atom/ns#" term="Slick" /><title>Comparaison d'Anorm et Slick pour l'accès aux bases de données relationnelles en Scala</title><content type="html">Anorm et Slick sont 2 librairies Scala qui permettent d'intéragir avec des bases de données relationnelles.&lt;br /&gt;
La première fait partie du framework Play (mais peut être utilisée&amp;nbsp;séparément&amp;nbsp; et propose d'écrire les requêtes en utilisant directement le langage SQL, la deuxième est l'outil officiel de la stack TypeSafe (la société derrière le langage Scala) et propose un DSL (Domain Specific Langage) plus fortement typé, pour générer du SQL.&lt;br /&gt;
&lt;br /&gt;
Nous allons comparer ces 2 outils et voir comment implémenter les cas d'utilisation classiques à travers l' exemple de l'application &lt;b&gt;&lt;a href="http://www.playframework.com/documentation/2.0.3/Samples"&gt;Computer Database&lt;/a&gt;&lt;/b&gt;.&lt;br /&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;
&lt;p&gt;Remarque : Slick propose plusieurs modes de fonctionnement dont le mode &lt;a href="http://slick.typesafe.com/doc/1.0.0/sql.html
"&gt;plain sql&lt;/a&gt; qui permet à l'instar d'Anorm d'écrire du "vrai SQL". Ce mode est préconisé lorsque l'on a besoin d'écrire une requête très spécifique difficilement exprimable avec le DSL. Dans cet article nous étudierons uniquement le mode "lifted embedding" qui est plus fréquemment utilisé.&lt;/p&gt;
&lt;h4&gt;
Définition des structures de données&lt;/h4&gt;
Avec Anorm, on définit 'case class' pour définir notre modèle, ainsi que des fonctions de mapping pour faire correspondre les resultats de requêtes avec des objets Scala :&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="java" name="code"&gt;case class Company(id: Pk[Long] = NotAssigned, name: String)
case class Computer(id: Pk[Long] = NotAssigned, name: String, introduced: Option[Date], discontinued: Option[Date], companyId: Option[Long])


object Company {
    
  /**
   * Parse a Company from a ResultSet
   */
  val simple = {
    get[Pk[Long]]("company.id") ≈
    get[String]("company.name") map {
      case id~name =&amp;gt; Company(id, name)
    }
  }
 //méthodes de lecture, insertion, mise à jour dans la base
}


object Computer {
  
  // -- Parsers
  
  /**
   * Parse a Computer from a ResultSet
   */
  val simple = {
    get[Pk[Long]]("computer.id") ~
    get[String]("computer.name") ~
    get[Option[Date]]("computer.introduced") ~
    get[Option[Date]]("computer.discontinued") ~
    get[Option[Long]]("computer.company_id") map {
      case id~name~introduced~discontinued~companyId =&amp;gt; Computer(id, name, introduced, discontinued, companyId)
    }
  }

  //méthodes de lecture, insertion, mise à jour dans la base
}
&lt;/pre&gt;
Le symbole '~' permet de représenter la composition des result sets en provenance de la base de données, puis de définir des tuples Scala à partir de ces données.
&lt;br /&gt;
&lt;br /&gt;
Avec Slick, en plus des case class, on décrit la structure des tables de la base de données, afin de pouvoir les manipuler à travers le DSL :

&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="java" name="code"&gt;case class Company(id: Option[Long], name: String)
case class Computer(id: Option[Long] = None, name: String, introduced: Option[Date]= None, discontinued: Option[Date]= None, companyId: Option[Long]=None)

object Companies extends Table[Company]("COMPANY") {

  def id = column[Long]("id", O.PrimaryKey, O.AutoInc)
  def name = column[String]("name", O.NotNull)
  def * = id.? ~ name &amp;lt;&amp;gt;(Company.apply _, Company.unapply _)
  def autoInc = * returning id
  
  //méthodes de lecture, insertion, mise à jour dans la base
}

object Computers extends Table[Computer]("COMPUTER") {

  def id = column[Long]("id", O.PrimaryKey, O.AutoInc)
  def name = column[String]("name", O.NotNull)
  def introduced = column[Date]("introduced", O.Nullable)
  def discontinued = column[Date]("discontinued", O.Nullable)
  def companyId = column[Long]("companyId", O.Nullable)

  def * = id.? ~ name ~ introduced.? ~ discontinued.? ~ companyId.? &amp;lt;&amp;gt;(Computer.apply _, Computer.unapply _)

  def autoInc = * returning id

//...
}
&lt;/pre&gt;
&lt;br /&gt;
&lt;h4&gt;
Récupération d'une liste d'entrées&lt;/h4&gt;
&lt;div&gt;
On va commencer par lister les marques d'ordinateurs (companies). On veut récupérer des tuples (id, name) sous forme de String (cette info sera uniquement utilisée pour l'affichage sur la page web).&lt;br /&gt;
&lt;br /&gt;
Avec Anorm, on écrit notre requête SQL puis on explicite la correspondance avec le modèle en utilisant la fonction map :&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="java" name="code"&gt;def options: Seq[(String,String)] = DB.withConnection { implicit connection =&amp;gt;
    SQL("select * from company order by name").as(Company.simple *).map(c =&amp;gt; c.id.toString -&amp;gt; c.name)
  }
&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;
Avec Slick on utilise les API de collections et les structures pour itérer sur les résultats de la requête générée :&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="java" name="code"&gt;def options: Seq[(String, String)] = DB.withSession { implicit session =&amp;gt;
      val query = (for {
        company &amp;lt;- Companies
      } yield (company.id, company.name)
        ).sortBy(_._2)
      query.list.map(row =&amp;gt; (row._1.toString, row._2))
  }&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h4&gt;
Récupération d'une liste d'entrées paginées à partir d'un filtre&lt;/h4&gt;
On complique un peu les choses, en introduisant la pagination, le tri et la recherche par filtres.
&lt;br /&gt;
Anorm : 
&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="java" name="code"&gt;def list(page: Int = 0, pageSize: Int = 10, orderBy: Int = 1, filter: String = "%"): Page[(Computer, Option[Company])] = {
    
    val offest = pageSize * page
    
    DB.withConnection { implicit connection =&amp;gt;
      
      val computers = SQL(
        """
          select * from computer 
          left join company on computer.company_id = company.id
          where computer.name like {filter}
          order by {orderBy} nulls last
          limit {pageSize} offset {offset}
        """
      ).on(
        'pageSize -&amp;gt; pageSize, 
        'offset -&amp;gt; offest,
        'filter -&amp;gt; filter,
        'orderBy -&amp;gt; orderBy
      ).as(Computer.withCompany *)

      val totalRows = count(filter)

      //count sera décrit plus bas

      Page(computers, page, offest, totalRows)
      
    }
    
  }
&lt;/pre&gt;
&lt;br /&gt;
Les paramètres entre&amp;nbsp;accolades&amp;nbsp;sont substitués à l'aide de la fonction 'on'.&lt;br /&gt;
&lt;br /&gt;
Ce code nécessite l'introduction d'une fonction 'Computer.withCompany' pour transformer les résultats du left join en une collection de type Seq[(Computer, Option[Company])] :&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="java" name="code"&gt;val withCompany = Computer.simple ~ (Company.simple ?) map {
  case computer~company =&amp;gt; (computer,company)
}
&lt;/pre&gt;
&lt;br /&gt;
Le caractère '?' permet de spécifier que la compagnie est optionnelle.

&lt;br /&gt;
&lt;br /&gt;
Slick :
&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="java" name="code"&gt; def list(page: Int = 0, pageSize: Int = 10, orderBy: Int = 1, filter: String = "%"): Page[(Computer, Option[Company])] = {

    val offset = pageSize * page

    DB.withSession { implicit session =&amp;gt;
        val query =
          (for {
            (computer, company) &amp;lt;- Computers leftJoin Companies on (_.companyId === _.id)
            if computer.name.toLowerCase like filter.toLowerCase()
          }
          yield (computer, company.id.?, company.name.?))
            .drop(offset)
            .take(pageSize)

        val totalRows = count(filter)
        val result = query.list.map(row =&amp;gt; (row._1, row._2.map(value =&amp;gt; Company(Option(value), row._3.get))))

        Page(result, page, offset, totalRows)
    }
  }&lt;/pre&gt;
&lt;br /&gt;
Ici on trouve une autre difficulté. On ne peut pas déclarer directement la jointure avec la compagnie comme optionnelle. On doit ruser en disant qu'on peut avoir un id et un nom, puis en utilisant la fonction map sur l'option d'id, on peut recréer notre type Option[Company] et renvoyer le bon résultat.&lt;br /&gt;
&lt;br /&gt;
Note : dans les 2 cas on utilise un type Page créé par nos soins pour gérer la pagination des données :
&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="java" name="code"&gt;case class Page[A](items: Seq[A], page: Int, offset: Long, total: Long) {
  lazy val prev = Option(page - 1).filter(_ &amp;gt;= 0)
  lazy val next = Option(page + 1).filter(_ =&amp;gt; (offset + items.size) &amp;lt; total)
}&lt;/pre&gt;
&lt;br /&gt;
&lt;h4&gt;
Insertion d'une entrée dans la base de données&lt;/h4&gt;
Anorm :&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="java" name="code"&gt;def insert(computer: Computer) = {
    DB.withConnection { implicit connection =&amp;gt;
      SQL(
        """
          insert into computer values (
            (select next value for computer_seq), 
            {name}, {introduced}, {discontinued}, {company_id}
          )
        """
      ).on(
        'name -&amp;gt; computer.name,
        'introduced -&amp;gt; computer.introduced,
        'discontinued -&amp;gt; computer.discontinued,
        'company_id -&amp;gt; computer.companyId
      ).executeUpdate()
    }
  }&lt;/pre&gt;
&lt;br /&gt;
Slick :&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="java" name="code"&gt;  def insert(computer: Computer) {
   DB.withSession { implicit session =&amp;gt;
      Computers.autoInc.insert(computer)
    }
  }&lt;/pre&gt;
&lt;br /&gt;
Note : pour effectuer les opérations au sein d'une transaction, il faut remplacer "DB.withConnection" (Anorm) ou "DB.withSession" (Slick) par "DB.withTransaction". Le bloc sera ensuite transactionnel. Si besoin les paramètres implicites "connection" et "session" proposent une méthode "rollback()".
&lt;br /&gt;
&lt;h4&gt;
&amp;nbsp;&lt;/h4&gt;
&lt;h4&gt;
Calcul du nombre d'éléments&lt;/h4&gt;
Anorm :&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="java" name="code"&gt;def count(filter: String) : Int = {
    DB.withConnection { implicit connection =&amp;gt;
     SQL(
        """
          select count(*) from computer 
          left join company on computer.company_id = company.id
          where computer.name like {filter}
        """
      ).on(
        'filter -&amp;gt; filter
      ).as(scalar[Long].single)
  }
&lt;/pre&gt;
&lt;br /&gt;
Slick :&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="java" name="code"&gt;def count(filter: String) : Int = DB.withSession { implicit session =&amp;gt;
      Query(Computers.where(_.name.toLowerCase like filter.toLowerCase).length).first
  }
&lt;/pre&gt;
&lt;br /&gt;
&lt;h4&gt;
Mise à jour d'une entrée&lt;/h4&gt;
Anorm :&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="java" name="code"&gt;def update(id: Long, computer: Computer) = {
    DB.withConnection { implicit connection =&amp;gt;
      SQL(
        """
          update computer
          set name = {name}, introduced = {introduced}, discontinued = {discontinued}, company_id = {company_id}
          where id = {id}
        """
      ).on(
        'id -&amp;gt; id,
        'name -&amp;gt; computer.name,
        'introduced -&amp;gt; computer.introduced,
        'discontinued -&amp;gt; computer.discontinued,
        'company_id -&amp;gt; computer.companyId
      ).executeUpdate()
    }
  }&lt;/pre&gt;
&lt;br /&gt;
Slick :
&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="java" name="code"&gt;def update(id: Long, computer: Computer) {
    DB.withSession { implicit session =&amp;gt;
        val computerToUpdate: Computer = computer.copy(Some(id))
        Query(Computers).where(_.id === id).update(computerToUpdate)
    }
  }&lt;/pre&gt;
&lt;h4&gt;
Suppression d'une entrée&lt;/h4&gt;
Anorm :&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="java" name="code"&gt;def delete(id: Long) = {
    DB.withConnection { implicit connection =&amp;gt;
      SQL("delete from computer where id = {id}").on('id -&amp;gt; id).executeUpdate()
    }
  }&lt;/pre&gt;
&lt;br /&gt;
Slick :&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="java" name="code"&gt;def delete(id: Long) {
    DB.withSession { implicit session =&amp;gt;
        Computers.where(_.id === id).mutate(_.delete)
    }
  }&lt;/pre&gt;
&lt;br /&gt;
&lt;b&gt;Conclusion&lt;/b&gt;&lt;br /&gt;
&lt;b&gt;&lt;br /&gt;&lt;/b&gt;
Slick et Anorm ont chacun leurs avantages et&amp;nbsp;inconvénients.&lt;br /&gt;
Voici mon avis sur leurs points positifs et négatifs respectifs ;&lt;br /&gt;
&lt;br /&gt;
&lt;u&gt;Anorm
&lt;/u&gt;&lt;br /&gt;
&lt;br /&gt;
Les&amp;nbsp;+ :&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Pas besoin d'apprendre un nouveau DSL&lt;/li&gt;
&lt;li&gt;Possibilité de tester directement ses requêtes SQL dans la base de données avant de les coller dans le code&lt;/li&gt;
&lt;/ul&gt;
Les - :&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Code SQL, donc potentiellement spécifique à une base de données en particulier&lt;/li&gt;
&lt;li&gt;Plus verbeux que Slick&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Requêtes non "type safe"&lt;/li&gt;
&lt;/ul&gt;
&lt;u&gt;&lt;br /&gt;&lt;/u&gt;
&lt;u&gt;Slick
&lt;/u&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div&gt;
Les&amp;nbsp;+ :&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;DSL typé&lt;/li&gt;
&lt;li&gt;Plus concis qu'Anorm. Ceci est particulièrement visible sur les opérations d'insertion/mise à jour de données&lt;/li&gt;
&lt;/ul&gt;
Les -&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Plus opaque, il est parfois difficile d'imaginer le code SQL qui se cache derrière le DSL. En cas d'erreur ça complique un peu les choses...&lt;/li&gt;
&lt;li&gt;La structure du framework incite à utiliser directement un driver spécifique à une base de données (par exemple la classe&amp;nbsp;&lt;span style="background-color: #f8f8f8; color: #333333; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; line-height: 19px; white-space: nowrap;"&gt;scala.slick.driver.MySQLDriver&lt;/span&gt;) mais le plugin Play-Slick aide à rendre le code plus générique&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;br /&gt;
Pour moi il n'y a pas vraiment de&amp;nbsp;vainqueur, je pense que le choix dépendra surtout du fait que vous vous sentiez plus à l'aise avec SQL ou avec les collections Scala pour parcourir vos données.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Bonus &lt;/b&gt;: Ce n'est qu'un pour le moment "proof of concept" mais il existe une version "type safe" d'Anorm, qui utilise les macros Scala lors de la phase de compilation pour renvoyer des résultats typés en fonction de la définition du schéma de la base de données. En plus de proposer un code plus concis, cette version d'Anorm apporterait aussi plus de sécurité au développeur :&amp;nbsp;&lt;a href="https://github.com/guillaumebort/anormtyped-demo"&gt;https://github.com/guillaumebort/anormtyped-demo&lt;/a&gt;&lt;br /&gt;
Personnellement je suis hyper-séduit par cette solution!&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Et vous, laquelle de ces deux librairies&amp;nbsp;préférez&amp;nbsp;vous?&amp;nbsp;&lt;/b&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/IUKF/~4/ALQp9biJTvU" height="1" width="1"/&gt;</content><link rel="replies" type="text/html" href="http://coffeebean.loicdescotte.com/2013/03/comparaison-danorm-et-slick-pour-lacces.html#comment-form" title="8 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1231386620637429487/posts/default/7557827649947251231?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1231386620637429487/posts/default/7557827649947251231?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/IUKF/~3/ALQp9biJTvU/comparaison-danorm-et-slick-pour-lacces.html" title="Comparaison d'Anorm et Slick pour l'accès aux bases de données relationnelles en Scala" /><author><name>Loïc Descotte</name><uri>https://plus.google.com/117447657524839844765</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-vc8OSlrrAtM/AAAAAAAAAAI/AAAAAAAAFRA/sNj_WKeU-vI/s512-c/photo.jpg" /></author><thr:total>8</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://coffeebean.loicdescotte.com/2013/03/comparaison-danorm-et-slick-pour-lacces.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUUNQHY-cSp7ImA9WhBTGEo.&quot;"><id>tag:blogger.com,1999:blog-1231386620637429487.post-7580096071869333810</id><published>2013-02-06T12:05:00.000+01:00</published><updated>2013-02-14T22:28:11.859+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2013-02-14T22:28:11.859+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Scala" /><category scheme="http://www.blogger.com/atom/ns#" term="Play" /><category scheme="http://www.blogger.com/atom/ns#" term="Slick" /><title>Un plugin Slick pour Play 2.1</title><content type="html">Un plugin Slick pour Play 2.1 a été initié par Typesafe, il permet d'utiliser Slick (un librairie d'accès aux bases de données relationnelles en Scala) facilement au sein de Play, avec en prime la génération automatique du schéma (évolutions). Le but ultime est que son code soit intégré à Play 2.2 pour que Slick soit utilisable par défaut. C'est encore au stade Beta mais vous pouvez déjà jouer avec en le récupérant ici : &lt;a href="https://github.com/freekh/play-slick"&gt;https://github.com/freekh/play-slick&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Si ça vous intéresse n'hésitez pas à contribuer, l'auteur &lt;a href="https://github.com/freekh"&gt;Fredrik Ekholdt&lt;/a&gt; est très abordable, il vient d'ailleurs d'intégrer&amp;nbsp;au plugin&amp;nbsp;ma modeste contribution permettant d'abstraire le driver jdbc utilisé (et donc de switcher facilement d'une base à une autre), donc merci Fredrik :)&lt;img src="http://feeds.feedburner.com/~r/blogspot/IUKF/~4/uv7hH7bYkso" height="1" width="1"/&gt;</content><link rel="replies" type="text/html" href="http://coffeebean.loicdescotte.com/2013/02/un-plugin-slick-pour-play-21.html#comment-form" title="0 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1231386620637429487/posts/default/7580096071869333810?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1231386620637429487/posts/default/7580096071869333810?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/IUKF/~3/uv7hH7bYkso/un-plugin-slick-pour-play-21.html" title="Un plugin Slick pour Play 2.1" /><author><name>Loïc Descotte</name><uri>https://plus.google.com/117447657524839844765</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-vc8OSlrrAtM/AAAAAAAAAAI/AAAAAAAAFRA/sNj_WKeU-vI/s512-c/photo.jpg" /></author><thr:total>0</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://coffeebean.loicdescotte.com/2013/02/un-plugin-slick-pour-play-21.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkUGQnc7eyp7ImA9WhNbGEo.&quot;"><id>tag:blogger.com,1999:blog-1231386620637429487.post-6347245998968707852</id><published>2012-11-20T08:22:00.000+01:00</published><updated>2013-01-22T16:57:03.903+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2013-01-22T16:57:03.903+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Scala" /><category scheme="http://www.blogger.com/atom/ns#" term="Play" /><category scheme="http://www.blogger.com/atom/ns#" term="Iteratee" /><category scheme="http://www.blogger.com/atom/ns#" term="HTML5" /><category scheme="http://www.blogger.com/atom/ns#" term="Realtime" /><category scheme="http://www.blogger.com/atom/ns#" term="NoSQL" /><category scheme="http://www.blogger.com/atom/ns#" term="Mongo" /><category scheme="http://www.blogger.com/atom/ns#" term="push" /><title>Push database -&gt; browser avec Mongo et Play</title><content type="html">Aujourd'hui je vous propose une expérience amusante à réaliser avec Play Framework 2.1 et la base de données NoSQL MongoDB.&lt;br /&gt;
Vous avez peut être entendu parler de ReactiveMongo, un driver Scala "asynchrone et réactif" pour Mongo. Il existe un plugin Play pour utiliser ce driver plus facilement au sein d'une webapp. Nous allons voir comment utiliser ces technologies pour récupérer un ensemble de messages de manière asynchrone et pour les pousser vers le navigateur en temps réel, dans une application de type "Twitter lite". Le but de notre prototype : &lt;b&gt;en laissant une page de recherche ouverte, on veut voir les nouveaux messages correspondant à cette recherche s'afficher dès leur enregistrement en base de données&lt;/b&gt;, sans effectuer de "pull" vers le serveur.&lt;br /&gt;
&lt;br /&gt;
&lt;a name='more'&gt;&lt;/a&gt;Côté browser nous allons utiliser la technologie SSE (Server-Sent Events).&lt;br /&gt;
Si on reprend la définition du &lt;a href="http://www.w3schools.com/html/html5_serversentevents.asp"&gt;W3C&lt;/a&gt;, SSE est le fait "qu'une page reçoive automatiquement les mises à jour d'un serveur". C'est donc une technique de push qui permet de s'abonner à des mises à jour et à afficher les nouvelles données sans effectuer de&amp;nbsp;requête&amp;nbsp;de rechargement.&lt;br /&gt;
&lt;br /&gt;
Note : certains auront remarqué que le principe de SSE est proche de celui des WebSockets. Si ces 2 techniques font partie d' HTML5, SSE est plus simple car il ne gère que la transmission de données que dans le sens serveur -&amp;gt; client, alors que WebSocket est bidirectionnel.&lt;br /&gt;
&lt;br /&gt;
Assez parlé, un peu de code (Scala) :&lt;br /&gt;
&lt;pre class="java" name="code"&gt; def search(filter: String) = Action { 
    val query = QueryBuilder().query(
                    BSONDocument("message" -&amp;gt; BSONRegex(filter, "")))

    //query results asynchronous cursor
    val cursor = 
        collection.find[JsValue](query, QueryOpts().tailable.awaitData)

    //create the enumerator
    val dataProducer = cursor.enumerate

    //stream the results
    Ok.stream(dataProducer through EventSource())
        .as("text/event-stream")
}
&lt;/pre&gt;
&lt;br /&gt;
L'objet "collection" est notre lien avec la base de données. Dans notre contrôleur Play, on crée un curseur qui renverra les nouveaux messages contenant notre filtre de recherche, au fur et à mesure de leur arrivée dans la base grâce à l'option "tailable.awaitData".&lt;br /&gt;
On utilise ensuite la méthode "Ok.stream" qui permet d'envoyer des résultats partiels au client dès leur disponibilité. L'objet "EventSource"&amp;nbsp;fait partie de l'API Iteratee de Play (voir &lt;a href="https://gist.github.com/3727850"&gt;cette page pour en savoir plus&lt;/a&gt;) et fournit un pont vers la fonction SSE définie côté client :&lt;br /&gt;
&lt;pre class="java" name="code"&gt;&amp;lt;script type="text/javascript" charset="utf-8"&amp;gt;
    var feed = new EventSource("/news/search?filter=@filter");
    feed.addEventListener('message', function(e) {
    var result  = jQuery.parseJSON(event.data);
    //[...]
&amp;lt;/script&amp;gt;
&lt;/pre&gt;
&lt;br /&gt;
On récupère enfin chaque nouveau message dans un objet javascript "result" afin de l'afficher dynamiquement.&lt;br /&gt;
&lt;br /&gt;
Note : lors de la commande "collection.find[JsValue](...)" les objets obtenus via la requête Mongo ont été automatiquement convertis au format JSON (ou JsValue) avant de les pousser sur la socket SSE.&lt;br /&gt;
Cela fonctionne grâce à un paramètre implicite (les fameux "implicits" de Scala) définissant une méthode de transformation. Pour profiter de ces implicits il suffit d'ajouter la ligne "import play.modules.reactivemongo.PlayBsonImplicits._".&lt;br /&gt;
&lt;br /&gt;
Note 2 : "dataProducer &lt;b&gt;through&lt;/b&gt; EventSource()" peut aussi s'écrire "dataProducer &lt;b&gt;&amp;amp;&amp;gt;&lt;/b&gt; EventSource()", selon les goûts...&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Vous pouvez récupérer le code complet de l'application &lt;a href="https://github.com/loicdescotte/Play2MongoSSE"&gt;ici&lt;/a&gt;.&lt;/b&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/IUKF/~4/AGznhJqw8Zw" height="1" width="1"/&gt;</content><link rel="replies" type="text/html" href="http://coffeebean.loicdescotte.com/2012/11/push-database-browser-avec-mongo-et-play.html#comment-form" title="0 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1231386620637429487/posts/default/6347245998968707852?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1231386620637429487/posts/default/6347245998968707852?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/IUKF/~3/AGznhJqw8Zw/push-database-browser-avec-mongo-et-play.html" title="Push database -&gt; browser avec Mongo et Play" /><author><name>Loïc Descotte</name><uri>https://plus.google.com/117447657524839844765</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-vc8OSlrrAtM/AAAAAAAAAAI/AAAAAAAAFRA/sNj_WKeU-vI/s512-c/photo.jpg" /></author><thr:total>0</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://coffeebean.loicdescotte.com/2012/11/push-database-browser-avec-mongo-et-play.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUIHR30zfCp7ImA9WhNTEEg.&quot;"><id>tag:blogger.com,1999:blog-1231386620637429487.post-7857449583452293402</id><published>2012-10-11T21:45:00.002+02:00</published><updated>2012-10-12T16:52:16.384+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-10-12T16:52:16.384+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Scala" /><category scheme="http://www.blogger.com/atom/ns#" term="Play" /><category scheme="http://www.blogger.com/atom/ns#" term="Play 2.0" /><category scheme="http://www.blogger.com/atom/ns#" term="ebook" /><title>Play.Rules!►Return : un nouveau chapitre d'introduction à Scala</title><content type="html">Dans&amp;nbsp;ce chapitre nous allons voir&amp;nbsp;l’intérêt&amp;nbsp;d'utiliser Scala à travers quelques exemples, les différences avec la version Java et surtout "pourquoi Scala colle à l'esprit de Play".&lt;br /&gt;
Ceci peut donc être vu comme un chapitre bonus, sans lien avec le tuto "Bookmarks", pour vous donner envie de découvrir Scala.&lt;br /&gt;
&lt;br /&gt;
Lire le chapitre :&amp;nbsp;&lt;a href="https://github.com/3monkeys/play.rules/blob/master/livre.play.deux/12-scala.md"&gt;https://github.com/3monkeys/play.rules/blob/master/livre.play.deux/12-scala.md&lt;/a&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/IUKF/~4/f7CYTPtdVwA" height="1" width="1"/&gt;</content><link rel="replies" type="text/html" href="http://coffeebean.loicdescotte.com/2012/10/playrulesreturn-un-nouveau-chapitre.html#comment-form" title="2 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1231386620637429487/posts/default/7857449583452293402?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1231386620637429487/posts/default/7857449583452293402?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/IUKF/~3/f7CYTPtdVwA/playrulesreturn-un-nouveau-chapitre.html" title="Play.Rules!►Return : un nouveau chapitre d'introduction à Scala" /><author><name>Loïc Descotte</name><uri>https://plus.google.com/117447657524839844765</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-vc8OSlrrAtM/AAAAAAAAAAI/AAAAAAAAFRA/sNj_WKeU-vI/s512-c/photo.jpg" /></author><thr:total>2</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://coffeebean.loicdescotte.com/2012/10/playrulesreturn-un-nouveau-chapitre.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DE8ERHw6fCp7ImA9WhJUF0w.&quot;"><id>tag:blogger.com,1999:blog-1231386620637429487.post-1699734929673918745</id><published>2012-09-15T15:38:00.000+02:00</published><updated>2012-09-15T15:46:45.214+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-09-15T15:46:45.214+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Scala" /><category scheme="http://www.blogger.com/atom/ns#" term="Iteratee" /><category scheme="http://www.blogger.com/atom/ns#" term="Play 2.0" /><title>Play2 : Les Iteratees expliqués aux humains... francophones!</title><content type="html">Dans le &lt;a href="http://coffeebean.loicdescotte.com/2012/08/experiment-play2-scala-iteratee-comet.html"&gt;post précédent&lt;/a&gt; nous avons vu comment envoyer des données de manière asynchrone vers le browser avec Play 2. Pour cela nous avons utilisé quelques fonctionnalités de l'API Iteratee offerte par Play Framework.&lt;br /&gt;
&lt;br /&gt;
Afin de pouvoir expliquer plus en profondeur les concepts derrière cette API, je viens de faire la traduction &lt;b&gt;en français &lt;/b&gt;d'un très bon article en anglais écrit&amp;nbsp;par un développeur travaillant chez Zenexity, la société éditrice de Play.&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Pour lire cet article intitulé "&lt;b&gt;Play2 : Les Iteratees expliqués aux humains... francophones!&lt;/b&gt;", &amp;nbsp;ça se passe ici :&amp;nbsp;&lt;a href="http://gist.github.com/3727850#file_iteratees_humains.md"&gt;http://gist.github.com/3727850#file_iteratees_humains.md&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
L'article original se trouve ici :&amp;nbsp;&lt;a href="http://mandubian.com/2012/08/27/understanding-play2-iteratees-for-normal-humans"&gt;http://mandubian.com/2012/08/27/understanding-play2-iteratees-for-normal-humans&lt;/a&gt;&lt;/div&gt;
&lt;img src="http://feeds.feedburner.com/~r/blogspot/IUKF/~4/GabhCyui9DM" height="1" width="1"/&gt;</content><link rel="replies" type="text/html" href="http://coffeebean.loicdescotte.com/2012/09/play2-les-iteratees-expliques-aux.html#comment-form" title="0 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1231386620637429487/posts/default/1699734929673918745?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1231386620637429487/posts/default/1699734929673918745?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/IUKF/~3/GabhCyui9DM/play2-les-iteratees-expliques-aux.html" title="Play2 : Les Iteratees expliqués aux humains... francophones!" /><author><name>Loïc Descotte</name><uri>https://plus.google.com/117447657524839844765</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-vc8OSlrrAtM/AAAAAAAAAAI/AAAAAAAAFRA/sNj_WKeU-vI/s512-c/photo.jpg" /></author><thr:total>0</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://coffeebean.loicdescotte.com/2012/09/play2-les-iteratees-expliques-aux.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0MCQHgycSp7ImA9WhJXEUQ.&quot;"><id>tag:blogger.com,1999:blog-1231386620637429487.post-8442852352810172277</id><published>2012-08-05T20:07:00.002+02:00</published><updated>2012-08-05T20:31:01.699+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-08-05T20:31:01.699+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Scala" /><category scheme="http://www.blogger.com/atom/ns#" term="Play" /><category scheme="http://www.blogger.com/atom/ns#" term="Iteratee" /><category scheme="http://www.blogger.com/atom/ns#" term="Play 2.0" /><category scheme="http://www.blogger.com/atom/ns#" term="Comet" /><title>Experiment : Play2 + Scala + Iteratee + Comet = Realtime Web</title><content type="html">Just a little experiment I've done with Play2, Scala and Iteratee to mixup some Twitter searches : see the POC and the explanations on Github &lt;a href="https://gist.github.com/3266376#file_mixed_tweets.md"&gt;here&lt;/a&gt;!&lt;img src="http://feeds.feedburner.com/~r/blogspot/IUKF/~4/c7Ozph5nrtw" height="1" width="1"/&gt;</content><link rel="replies" type="text/html" href="http://coffeebean.loicdescotte.com/2012/08/experiment-play2-scala-iteratee-comet.html#comment-form" title="0 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1231386620637429487/posts/default/8442852352810172277?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1231386620637429487/posts/default/8442852352810172277?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/IUKF/~3/c7Ozph5nrtw/experiment-play2-scala-iteratee-comet.html" title="Experiment : Play2 + Scala + Iteratee + Comet = Realtime Web" /><author><name>Loïc Descotte</name><uri>https://plus.google.com/117447657524839844765</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-vc8OSlrrAtM/AAAAAAAAAAI/AAAAAAAAFRA/sNj_WKeU-vI/s512-c/photo.jpg" /></author><thr:total>0</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://coffeebean.loicdescotte.com/2012/08/experiment-play2-scala-iteratee-comet.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkQGQnw5fyp7ImA9WhVbGE0.&quot;"><id>tag:blogger.com,1999:blog-1231386620637429487.post-4376002211291325323</id><published>2012-06-01T08:47:00.000+02:00</published><updated>2012-06-04T13:12:03.227+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-06-04T13:12:03.227+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Scala" /><category scheme="http://www.blogger.com/atom/ns#" term="Akka" /><category scheme="http://www.blogger.com/atom/ns#" term="acteurs" /><title>Akka : à la découverte des acteurs</title><content type="html">Akka est un framework permettant de gérer des problématiques de parallélisation et d'asynchronisme, basé sur un système d'acteurs. Les acteurs sont des objets capables de communiquer entre eux par messages pour échanger des ordres d’exécution et des informations sur leur état.&lt;br /&gt;
&lt;br /&gt;
Dans cet article nous allons étudier un cas assez simple : comment appliquer une transformation (une multiplication par deux) sur une liste d'entiers en parallélisant les calculs.&lt;br /&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Pour ceci nous allons créer un système avec plusieurs acteurs :&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Un master qui va dispatcher le travail puis récupérer les résultats&lt;/li&gt;
&lt;li&gt;Des workers qui vont traiter individuellement les transformations d'entiers&lt;/li&gt;
&lt;/ul&gt;
Cette première portion de code va initialiser le système et créer les acteurs. On démarre le master en lui envoyant un message de type Start.&lt;br /&gt;
&lt;div&gt;
&lt;pre class="java" name="code"&gt;    
final int nbWorkers = 6;
List&amp;lt;Integer&amp;gt; numbers = Arrays.asList(1, 5, 15, 22, 66, 55);
ActorSystem system = ActorSystem.create("mySystem");
ActorRef master = system.actorOf(new Props(new UntypedActorFactory() {
  public UntypedActor create() {
    return new Master(nbWorkers, numbers);
  }
}), "master");
Start startMessage = new Start();
master.tell(startMessage);
&lt;/pre&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Au moment de sa création, le master va déclarer un routeur capable de répartir les traitements demandés sur un nombre de nœuds définis par nos soins (ici on en a 6) .&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="java" name="code"&gt;public class Master extends UntypedActor {
  private List&amp;lt;Integer&amp;gt; numbers;
  private final ActorRef workerRouter;
  long start = System.currentTimeMillis();

  public Master(int nbWorkers, List&amp;lt;Integer&amp;gt; numbers) {
    transformedNumbers = new ArrayList&amp;lt;Integer&amp;gt;();
    this.numbers = numbers;
    //create the worker dispatcher
    workerRouter = this.getContext().actorOf(new Props(Worker.class).withRouter(new RoundRobinRouter(nbWorkers)), "workerRouter");
    System.out.println("master and router created");
  }
&lt;/pre&gt;
&lt;br /&gt;
Voyons maintenant comment le master répond aux messages. Cet acteur reconnaît deux types de messages : Start et Response.
Leur code est assez sommaire :&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="java" name="code"&gt;public class Start{}
&lt;/pre&gt;
&lt;pre class="java" name="code"&gt;
public class Result{
    public Result(int value) {
      this.value = value;
    }
    public int value;
  }
&lt;/pre&gt;
&lt;br /&gt;
Le premier est vide, il permet simplement de démarrer le master pour lui demander de dispatcher le travail de calcul envoyant chaque entier à un worker (comme nous l'avons vu plus haut). L'autre est un simple conteneur qui permet aux workers de renvoyer les résultats partiels du calcul.&lt;br /&gt;
&lt;br /&gt;
Lé méthode "onReceive" que l'on définit dans le master reçoit les messages qui sont adressés à celui ci :
&lt;br /&gt;
&lt;pre class="java" name="code"&gt;@Override
  public void onReceive(Object message) {
    if(message instanceof Start){
      System.out.println("master received a start event");
      //dispatch
      for (Integer number : numbers){
        // send to a worker
        workerRouter.tell(number, getSelf());
      }
    }
    else if(message instanceof Result){
      System.out.println("master received result event");
      Result result = (Result) message;
      //join
      transformedNumbers.add(result.value);
      if(transformedNumbers.size() == numbers.size()){
        Duration duration = Duration.create(System.currentTimeMillis() - start, TimeUnit.MILLISECONDS);
        System.out.println(transformedNumbers.size() + " numbers computed in " + duration);
        //stop master and its workers
        getContext().stop(getSelf());
        getContext().system().shutdown();
      }
    }
  }
&lt;/pre&gt;
&lt;div&gt;
&lt;br /&gt;
Une fois que le master a récupéré le nombre de réponses attendues, le travail est terminé et on peut afficher le résultat.&lt;br /&gt;
L'instruction "tell" permet de travailler de manière asynchrone : lorsque l'on demande à un worker de traiter un entier, on continue à exécuter le code pour traiter les éléments suivants sans attendre le résultat, qui sera communiqué au master à l'aide d'une notification.&lt;/div&gt;
&lt;br /&gt;
Enfin, voici le code de la classe Worker :&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="java" name="code"&gt;public class Worker extends UntypedActor {

  @Override
  public void onReceive(Object message) {
    System.out.println("worker received an event");
    if(message instanceof  Integer){
      int number = (Integer) message;
      int transformedNumber = tranform(number);
      //send result to master
      getSender().tell(new Result(transformedNumber), self());
    }
  }

  private int tranform(int number){
    try {
      Thread.sleep(4000);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    return number *2;
  }
}
&lt;/pre&gt;
&lt;br /&gt;
La méthode transform contient le code de la transformation. On introduit volontairement un "sleep" de 4 secondes pour allonger le traitement et mesurer plus facilement le gain de la parallélisation.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;
&lt;b&gt;Premières observations&lt;/b&gt;
&lt;/div&gt;
&lt;br /&gt;
Définir plusieurs workers permet de répartir le traitement sur plusieurs threads en faisant abstraction de la programmation&amp;nbsp;parallèle :&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Avec un seul worker, transformer les 6 entiers demandés prend environ 24 secondes&lt;/li&gt;
&lt;li&gt;Avec 4 workers : environ 8 secondes&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Avec 6 workers : environ 4 secondes&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div&gt;
Pour un nombre de workers supérieur ou égal au nombre d'éléments, le temps de calcul revient à peu près à passer une seule fois dans le sleep de 4 secondes : on n'attend pas la fin d'un calcul et du sleep associé pour passer aux itérations suivantes.&lt;/div&gt;
&lt;div&gt;
Dans notre cas comme il y a des phases d'attente on peut même aller à un nombre de workers supérieurs au nombre de coeurs de la machine (j'ai lancé ce code sur un dual-core). &amp;nbsp;Ceci peut également être pertinent lorsqu'on attend la réponse d'un webservice par exemple ou pour tout autre type d'entrées/sorties.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;
&lt;b&gt;Quelques modifications&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
On aimerait pouvoir récupérer le résultat du traitement depuis une méthode appelante.&lt;br /&gt;
Cependant si celle ci n'est pas gérée par un acteur, on ne peut pas répondre directement depuis notre master à l'aide d'un "tell". On passe alors par l'API Future d'Akka.&lt;br /&gt;
Un future permet de lancer un traitement en&amp;nbsp;parallèle&amp;nbsp;(dans un thread séparé) puis de récupérer le résultat.&lt;br /&gt;
Par exemple :&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="java" name="code"&gt;public static void main(String[]args) throws Exception{
    ActorSystem system = ActorSystem.create("mySystem");

    Future&amp;lt;String&amp;gt; f1 = future(new Callable&amp;lt;String&amp;gt;() {
      public String call() throws Exception {
        Thread.sleep(4000);
        return "You String is ready !!";
      }
    }, system.dispatcher());
    Timeout timeout = new Timeout(Duration.parse("30 seconds"));
    String result = Await.result(f1, timeout.duration());
    System.out.println(result);
  }
&lt;/pre&gt;
&lt;br /&gt;
Note : On utilise ici la classe Future d'Akka et non celle du JDK. Un des avantages de cette version est de permettre la récupération de la valeur dès qu'elle est disponible sans avoir à vérifier&amp;nbsp;périodiquement&amp;nbsp;que le traitement est terminé.&lt;br /&gt;
&lt;br /&gt;
On peut utiliser le même mécanisme pour obtenir la réponse d'un acteur une fois ses taches terminées.&lt;br /&gt;
La méthode Patterns.ask permet de définir un acteur implicite auquel notre master pourra répondre à travers un objet de type Future :&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="java" name="code"&gt;Future future = Patterns.ask(master, startMessage, timeout);
List&amp;lt;Integer&amp;gt; result = (List&amp;lt;Integer&amp;gt;) Await.result(future, timeout.duration());
&lt;/pre&gt;
&lt;br /&gt;
On peut ainsi imaginer une méthode qui appelle notre système d'acteurs et qui retourne le résultat :&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="java" name="code"&gt;public List&amp;lt;Integer&amp;gt; transform(List&amp;lt;Integer&amp;gt; numbers){
 ActorSystem system = ActorSystem.create("mySystem");
    ActorRef master = system.actorOf(new Props(new UntypedActorFactory() {
      public UntypedActor create() {
        System.out.println("create master");
        return new Master(nbWorkers, numbers);
      }
    }), "master");
    Start startMessage =  new Start();
    Timeout timeout = new Timeout(Duration.parse("30 seconds"));
    Future future = Patterns.ask(master, startMessage, timeout);
    List&amp;lt;Integer&amp;gt; result = (List&amp;lt;Integer&amp;gt;) Await.result(future, timeout.duration());
    system.shutdown();
 return result;
  }
&lt;/pre&gt;
&lt;br /&gt;
Pour renvoyer le message depuis le master, on garde une référence de l'expéditeur initial (déclaré&amp;nbsp;implicitement&amp;nbsp;lors de l'appel de 'ask') pour pouvoir lui répondre plus tard.&lt;br /&gt;
Attention, appeler la méthode 'getSender' en fin de traitement renverrait le message au dernier expéditeur, dans ce cas ce serait un worker.&lt;br /&gt;
On sauvegarde donc cette référence dans le bloc "Start" du worker :&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="java" name="code"&gt;public class Master extends UntypedActor {
  
  private ActorRef initialSender;
 ...

if(message instanceof Start){
  this.initialSender = getSender();
 ... 
}

if(message instanceof Response){
if(transformedNumbers.size() == numbers.size()){
    reply();
  }
...
}

public void reply(){
    initialSender.tell(transformedNumbers);
    //stop master and its workers
    getContext().stop(getSelf());
  }
}
&lt;/pre&gt;
&lt;br /&gt;
Note : Attention à l'utilisation de la classe Await.result qui est bloquante (d'où l'obligation d'utiliser un timeout). Ici cela ne pose pas de problème car elle intervient après avoir lancé tous les calculs en parallèle mais l'utiliser à un mauvais endroit aurait un impact sur les performances.&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Pour terminer ce long article, Akka est un framework écrit avec le langage Scala, il propose donc naturellement une API Scala pour manipuler les acteurs.
Scala permet d'écrire un code un peu plus élégant que Java pour ce genre de choses (par exemple en évitant les "cast"). Voici à quoi pourrait ressembler un worker en Scala :

&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="java" name="code"&gt;class Worker extends Actor { 
    def receive = {
 case Int(number) =&amp;gt; 
  sender ! number * 2
    }
&lt;/pre&gt;
&lt;br /&gt;
Vous pouvez télécharger le code source des exemples &lt;a href="http://dl.dropbox.com/u/7549438/blog/akka-coffeebean.zip"&gt;ici&lt;/a&gt;.
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/IUKF/~4/gOCAPlWeksg" height="1" width="1"/&gt;</content><link rel="replies" type="text/html" href="http://coffeebean.loicdescotte.com/2012/06/akka-la-decouverte-des-acteurs.html#comment-form" title="3 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1231386620637429487/posts/default/4376002211291325323?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1231386620637429487/posts/default/4376002211291325323?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/IUKF/~3/gOCAPlWeksg/akka-la-decouverte-des-acteurs.html" title="Akka : à la découverte des acteurs" /><author><name>Loïc Descotte</name><uri>https://plus.google.com/117447657524839844765</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-vc8OSlrrAtM/AAAAAAAAAAI/AAAAAAAAFRA/sNj_WKeU-vI/s512-c/photo.jpg" /></author><thr:total>3</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://coffeebean.loicdescotte.com/2012/06/akka-la-decouverte-des-acteurs.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUMMRHk9eSp7ImA9WhVQF08.&quot;"><id>tag:blogger.com,1999:blog-1231386620637429487.post-2400228597009920376</id><published>2012-04-06T17:48:00.003+02:00</published><updated>2012-04-06T17:51:25.761+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-04-06T17:51:25.761+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Play" /><category scheme="http://www.blogger.com/atom/ns#" term="HTML5" /><title>HTML5 input tags module for Play 2.0</title><content type="html">First try on Play2 module writing!&lt;br /&gt;
You can learn more and checkout the project here : &lt;a href="https://github.com/loicdescotte/Play2-HTML5Tags"&gt;https://github.com/loicdescotte/Play2-HTML5Tags&lt;/a&gt;&lt;br /&gt;
Any suggest or idea is welcome!&lt;img src="http://feeds.feedburner.com/~r/blogspot/IUKF/~4/gkB91YGznYU" height="1" width="1"/&gt;</content><link rel="replies" type="text/html" href="http://coffeebean.loicdescotte.com/2012/04/html5-input-tags-module-for-play-20.html#comment-form" title="0 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1231386620637429487/posts/default/2400228597009920376?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1231386620637429487/posts/default/2400228597009920376?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/IUKF/~3/gkB91YGznYU/html5-input-tags-module-for-play-20.html" title="HTML5 input tags module for Play 2.0" /><author><name>Loïc Descotte</name><uri>https://plus.google.com/117447657524839844765</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-vc8OSlrrAtM/AAAAAAAAAAI/AAAAAAAAFRA/sNj_WKeU-vI/s512-c/photo.jpg" /></author><thr:total>0</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://coffeebean.loicdescotte.com/2012/04/html5-input-tags-module-for-play-20.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CU8GRng9fip7ImA9WhVTFUw.&quot;"><id>tag:blogger.com,1999:blog-1231386620637429487.post-2758472355822554060</id><published>2012-02-29T12:10:00.001+01:00</published><updated>2012-02-29T12:10:27.666+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-29T12:10:27.666+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="programmez" /><category scheme="http://www.blogger.com/atom/ns#" term="Play" /><category scheme="http://www.blogger.com/atom/ns#" term="magazine" /><title>Un article sur Play Framework dans le magazine Programmez</title><content type="html">J'ai eu l'honneur il y a quelques mois d'écrire quelques pages pour présenter Play Framework dans le magazine Programmez.&lt;br /&gt;
Cet article vient de paraître, vous pouvez le découvrir dans &lt;a href="http://www.programmez.com/magazine.php"&gt;le dernier numéro&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
N.B : Malheureusement l'article ne couvre pas la prochaine version du framework annoncée pour Avril (il a en fait été rédigé au mois d'Octobre dernier...)&lt;img src="http://feeds.feedburner.com/~r/blogspot/IUKF/~4/CHmrBYKJeWE" height="1" width="1"/&gt;</content><link rel="replies" type="text/html" href="http://coffeebean.loicdescotte.com/2012/02/un-article-sur-play-framework-dans-le.html#comment-form" title="2 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1231386620637429487/posts/default/2758472355822554060?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1231386620637429487/posts/default/2758472355822554060?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/IUKF/~3/CHmrBYKJeWE/un-article-sur-play-framework-dans-le.html" title="Un article sur Play Framework dans le magazine Programmez" /><author><name>Loïc Descotte</name><uri>https://plus.google.com/117447657524839844765</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-vc8OSlrrAtM/AAAAAAAAAAI/AAAAAAAAFRA/sNj_WKeU-vI/s512-c/photo.jpg" /></author><thr:total>2</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://coffeebean.loicdescotte.com/2012/02/un-article-sur-play-framework-dans-le.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkMARn89cCp7ImA9WhRaFEQ.&quot;"><id>tag:blogger.com,1999:blog-1231386620637429487.post-1726807602566823902</id><published>2012-02-17T15:31:00.002+01:00</published><updated>2012-02-17T15:54:07.168+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-17T15:54:07.168+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Play" /><category scheme="http://www.blogger.com/atom/ns#" term="Kotlin" /><title>Kotlin : premiers essais avec IntelliJ IDEA</title><content type="html">Cette semaine, Jetbrains a mis disposition le code source de Kotlin &lt;a href="https://github.com/JetBrains/kotlin"&gt;sur Github&lt;/a&gt;.&lt;br /&gt;
On peut y télécharger le runtime, le compilateur et un plugin pour IntelliJ IDEA (attention, il faut la dernière version 'EAP' de l'IDE pour que cela fonctionne).&lt;br /&gt;
Voyons ensemble comment essayer ce nouveau langage en quelques lignes de code.&lt;br /&gt;
&lt;br /&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Une fois le plugin IDEA installé, on peut créer un nouveau fichier Kotlin en utilisant menu "New" --&amp;gt; "Kotlin file"
 
L'IDE demandera alors le chemin vers le runtime Kotlin.
Après avoir renseigné ce chemin, on peut commencer à coder!&lt;br /&gt;
&lt;br /&gt;
Pour commencer, on crée une méthode main :&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="java" name="code"&gt;fun main(args : Array&amp;lt;String&amp;gt;) {
}&lt;/pre&gt;
&lt;br /&gt;
Testons maintenant quelques fonctionnalités. La fonction &lt;i&gt;'filter'&lt;/i&gt; disponible sur les collections prend en paramètre une autre fonction :

&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="java" name="code"&gt;    val list1 = arrayList(1, 2, 3, 4, 5)
    println(list1.filter{it -&amp;gt; it&amp;gt;2})
&lt;/pre&gt;
&lt;br /&gt;
Cette fonction est disponible même sur les collections Java (ici on manipule une ArrayList) grâce au mécanisme d'extension de Kotlin (&lt;a href="http://confluence.jetbrains.net/display/Kotlin/Extension+functions"&gt;voir doc&lt;/a&gt;).&lt;br /&gt;
Dans notre exemple, la fonction passée en paramètre demande de ne retourner que les nombres superieurs à 2.
La sortie sera donc : 3,4,5&lt;br /&gt;
&lt;br /&gt;
Comme cette fonction ne prend qu'un paramètre, on peut simplifier son écriture comme ceci : 
&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="java" name="code"&gt; println(list1.filter{it&amp;gt;2})
&lt;/pre&gt;
&lt;br /&gt;
La fonction &lt;i&gt;'map'&lt;/i&gt; transforme une collection en une autre collection en appliquant une fonction à chaque élément :

&lt;br /&gt;
&lt;pre class="java" name="code"&gt;    val list2 = arrayList("bob", "joe", "john")
    println(list2.map{
        "Hello " + it.toUpperCase()
    })
&lt;/pre&gt;
&lt;br /&gt;
On peut noter que l'inférence de type fonctionne bien dans l'IDE. En effet, après le mot 'it' IDEA nous propose toutes les fonctions relatives au type String, qu'il a pu déterminer en analysant la construction de la list 'list2'.&lt;br /&gt;
Note : on aurait pu écrire explicitement le type de cette liste de cette manière : val list2: Array&amp;lt;String&amp;gt; = arrayList("bob", "joe", "john")
&lt;br /&gt;
&lt;br /&gt;
Dans un style plus "framework Web", définission maintenant une fonction 'get' qui prend en paramètre une route (une URL) et une fonction à exécuter lors de l'appel de cette URL :

&lt;br /&gt;
&lt;pre class="java" name="code"&gt;fun get(route: String, process : () -&amp;gt; String) {
    val response = process()
    println("added route $route : " + response)
}
&lt;/pre&gt;
&lt;div&gt;
&lt;br /&gt;
Note : on observe au passage la syntaxe '$route' qui permet d'insérer une expression dans un string.&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
Kotlin permet de passer le corps d'une fonction à l'exterieur des parenthèses si cette fonction est le dernier paramètre de la fonction englobante.&lt;br /&gt;
&lt;div&gt;
Derrière cette phrase compliquée, on peut voir que l'on peut appeler notre fonction comme ceci :&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;
&lt;pre class="java" name="code"&gt;    get("/hello") {
        val name = "bob"
        "&amp;lt;h1&amp;gt;hello $name&amp;lt;/h1&amp;gt;"
    }
&lt;/pre&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
On a donc une fonction 'get' qui peut être appelée en utilisant la même structure que &lt;i&gt;'map'&lt;/i&gt;, &lt;i&gt;'filter'&lt;/i&gt; ou même qu'une simple boucle &lt;i&gt;'while'&lt;/i&gt;. En exécutant le code ci-dessus, on a bien &lt;b&gt;"&amp;lt;h1&amp;gt;hello bob &amp;lt;/h1&amp;gt;"&lt;/b&gt; dans la console.&lt;br /&gt;
&lt;br /&gt;
En conclusion, ce premier aperçu est plutôt positif, l'IDE répond bien et semble tout à fait fonctionnel pour une preview.
En plus, l'équipe de Kotlin &lt;a href="https://twitter.com/#!/nmartignole/status/169858537323892737"&gt;a annoncé&lt;/a&gt; vouloir faire fonctionner Play Framework avec Kotlin!&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Pour en savoir plus sur ce langage, vous pouvez visiter &lt;a href="http://confluence.jetbrains.net/display/Kotlin/Welcome"&gt;cette page&lt;/a&gt; et découvrir d'autres fonctionnalités comme le pattern matching, les properties, les generics (bien plus puissants qu'en Java)...

Et si vous avez la flemme de configurer IntelliJ IDEA, vous pouvez toujours jouer avec la &lt;a href="http://kotlin-demo.jetbrains.com/"&gt;Web Demo&lt;/a&gt;!
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/IUKF/~4/tVkBFBNzqkk" height="1" width="1"/&gt;</content><link rel="replies" type="text/html" href="http://coffeebean.loicdescotte.com/2012/02/kotlin-premiers-essais-avec-intellij.html#comment-form" title="1 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1231386620637429487/posts/default/1726807602566823902?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1231386620637429487/posts/default/1726807602566823902?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/IUKF/~3/tVkBFBNzqkk/kotlin-premiers-essais-avec-intellij.html" title="Kotlin : premiers essais avec IntelliJ IDEA" /><author><name>Loïc Descotte</name><uri>https://plus.google.com/117447657524839844765</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-vc8OSlrrAtM/AAAAAAAAAAI/AAAAAAAAFRA/sNj_WKeU-vI/s512-c/photo.jpg" /></author><thr:total>1</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://coffeebean.loicdescotte.com/2012/02/kotlin-premiers-essais-avec-intellij.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0YDSXk9cSp7ImA9WhRUF0s.&quot;"><id>tag:blogger.com,1999:blog-1231386620637429487.post-3299545204359391967</id><published>2012-01-28T15:42:00.001+01:00</published><updated>2012-01-28T16:39:38.769+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-28T16:39:38.769+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Play" /><category scheme="http://www.blogger.com/atom/ns#" term="JUG" /><title>Présentation Play au Togo JUG : les slides</title><content type="html">&lt;a href="http://k33g.github.com/"&gt;Philippe&lt;/a&gt; et moi avons eu le plaisir de faire une présentation sur Play Framework (en versions 1.x et 2.0) pour le Togo JUG ce matin.&lt;br /&gt;
&lt;br /&gt;
Les slides (présentation du framework, tutoriels...) sont disponibles ici : &lt;a href="http://3monkeys.github.com/prez.play/"&gt;http://3monkeys.github.com/prez.play/&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note : pour les visionner il vaut mieux utiliser un navigateur sous WebKit, par exemple Chrome ou Safari.&lt;img src="http://feeds.feedburner.com/~r/blogspot/IUKF/~4/Q3X14F2UKGg" height="1" width="1"/&gt;</content><link rel="replies" type="text/html" href="http://coffeebean.loicdescotte.com/2012/01/presentation-play-au-togo-jug-les.html#comment-form" title="0 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1231386620637429487/posts/default/3299545204359391967?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1231386620637429487/posts/default/3299545204359391967?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/IUKF/~3/Q3X14F2UKGg/presentation-play-au-togo-jug-les.html" title="Présentation Play au Togo JUG : les slides" /><author><name>Loïc Descotte</name><uri>https://plus.google.com/117447657524839844765</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-vc8OSlrrAtM/AAAAAAAAAAI/AAAAAAAAFRA/sNj_WKeU-vI/s512-c/photo.jpg" /></author><thr:total>0</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://coffeebean.loicdescotte.com/2012/01/presentation-play-au-togo-jug-les.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEcASXk5eCp7ImA9WhVTFU4.&quot;"><id>tag:blogger.com,1999:blog-1231386620637429487.post-3254262590656367937</id><published>2011-12-25T11:50:00.001+01:00</published><updated>2012-02-29T18:20:48.720+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-29T18:20:48.720+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Scala" /><category scheme="http://www.blogger.com/atom/ns#" term="Scalatra" /><category scheme="http://www.blogger.com/atom/ns#" term="Scalate" /><title>Premiers pas avec Scalatra</title><content type="html">Scalatra est un framework Web ultra léger pour le langage Scala inspiré par Sinatra, un framework très populaire dans le monde Ruby.
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-vzAxLoQMZ18/Tvb0E0y7VKI/AAAAAAAADBA/I9RiutAx7ss/s1600/scalatra_logo.png" imageanchor="1"&gt;&lt;img border="0" height="92" src="http://3.bp.blogspot.com/-vzAxLoQMZ18/Tvb0E0y7VKI/AAAAAAAADBA/I9RiutAx7ss/s400/scalatra_logo.png" width="132" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;
Scalatra privilégie une approche très simple basée sur les principes REST. Pour effectuer une action, on part d'une méthode HTTP et d'une route (URL d'accès à la fonction), auxquelles on ajoute le traitement désiré :

&lt;br /&gt;
&lt;pre class="java" name="code"&gt;get("/hello") {
    "hello!"
}
&lt;/pre&gt;
&lt;br /&gt;
Avec cette approche et la manipulation XML proposée en Scala, on peut déclarer et renvoyer du contenu comme ceci :
&lt;br /&gt;
&lt;pre class="java" name="code"&gt;get("/hello") {
  &amp;lt;html&amp;gt;
      &amp;lt;body&amp;gt;
        &amp;lt;h1&amp;gt;Hello!&amp;lt;/h1&amp;gt;
     &amp;lt;/body&amp;gt;
   &amp;lt;/html&amp;gt;
}
&lt;/pre&gt;
On peut facilement ajouter des paramètres dans l'URL : 
&lt;br /&gt;
&lt;pre class="java" name="code"&gt;get("/hello/:name") { 
    &amp;lt;html&amp;gt;
      &amp;lt;body&amp;gt;
        &amp;lt;h1&amp;gt;Hello {params("name")} !&amp;lt;/h1&amp;gt;
      &amp;lt;/body&amp;gt;
    &amp;lt;/html&amp;gt;
  }
&lt;/pre&gt;
Renvoyer du contenu XML (ou JSON ou ce qu'on veut) pour exposer un service REST :

&lt;br /&gt;
&lt;pre class="java" name="code"&gt;get("/persons"){
 contentType="application/xml"
 &amp;lt;xml&amp;gt;
     &amp;lt;persons&amp;gt;{
         Database.entries.map { 
                    entry =&amp;gt;  &amp;lt;person&amp;gt;{entry}&amp;lt;/person&amp;gt; 
                }
     }&amp;lt;/persons&amp;gt;
 &amp;lt;/xml&amp;gt; 
 }
&lt;/pre&gt;
Faire un POST pour enregistrer de nouvelles données :
&lt;br /&gt;
&lt;pre class="java" name="code"&gt;post("/person"){
 val name = params("name")
 Database.addEntry(name)
 redirect("/persons")
  }
&lt;/pre&gt;
Remarque : Pour tester la méthode ci-dessus, on peut par exemple utiliser curl en ligne de commande :

&lt;br /&gt;
&lt;pre class="java" name="code"&gt;curl for test: curl --data "name=jim" http://localhost:8080/person
&lt;/pre&gt;
&lt;br /&gt;
On peut aussi rediriger l'action vers un template :
&lt;br /&gt;
&lt;pre class="java" name="code"&gt; get("/hello2/:name") {
      templateEngine.layout("hello-scalate.scaml", Map("name" -&amp;gt; params("name")))
  }
&lt;/pre&gt;
Scalatra est livré par défaut avec le moteur de template Scalate, qui est compatible avec plusieurs formats de templates.

Voici un exemple avec le format scaml : 

&lt;br /&gt;
&lt;pre class="xml" name="code"&gt;//redefinition du titre dans le layout par défaut
- attributes("title") 
//paramètre de requête
-@ val name: String

%h1 Welcome!
%p Hello, how are you #{name} ?
&lt;/pre&gt;
Enfin, on peut définir les actions à effecter en cas d'erreur : 

&lt;br /&gt;
&lt;pre class="java" name="code"&gt;
notFound { 
&amp;lt;h1&amp;gt;Nothing found here&amp;lt;/h1&amp;gt;
&amp;lt;img src=&amp;quot;/images/404.jpg&amp;quot; /&amp;gt;        
}
&lt;/pre&gt;
Le framework fonctionne avec l'outil de build SBT. Un support des WebSockets est proposé à travers la librairie Socket.IO.
En utilisant Jetty, le conteneur par défaut de Scalatra, on peut recharger le code à chaud (plus ou moins rapidement).

Pour cela on le démarre avec la commande suivante : 
&lt;br /&gt;
&lt;pre class="java" name="code"&gt; sbt
 &amp;gt; container:start
   &amp;gt; ~ aux-compile
&lt;/pre&gt;
Dans cet exemple, j'ai simulé à la base de données avec un "object" Scala. Un object est l'équivalent d'un singleton : c'est une classe qui possède une instance unique.

&lt;br /&gt;
&lt;pre class="java" name="code"&gt;object Database{
 //shared entries (simulate database)
 var entries = List("bob", "joe", "john") 
 def addEntry(name: String){
     entries = entries:+name
 }
}
&lt;/pre&gt;
On pourra facilement remplacer cette implémentation par une vraie base de données. Si vous n'avez pas besoin d'une base SQL (ce qui est en fait souvent le cas), vous pouvez regarder des choses plus simples comme la base de données objet &lt;a href="http://neodatis.wikidot.com/"&gt;NeoDatis&lt;/a&gt; qui supporte officiellement Scala. Pour des besoins de scalabilité plus importants, vous pouvez aussi jeter un oeil du côté de MongoDB et de Casbah (son toolkit Scala).
Avec ce genre d'outils vous conserverez une architecture simple, pas besoin de s'embêter avec des frameworks à la Spring, le langage apporte tout ce qu'il faut pour &lt;a href="http://jboner.github.com/2008/10/06/real-world-scala-dependency-injection-di.html"&gt;gérer l'injection de dépendance nativement&lt;/a&gt;.

Pour conclure, Scalatra nous prouve que contrairement aux idées reçues, on peut faire des choses extrêmement simples et efficaces en Scala avec des API bien pensées.
Si vous cherchez quelque chose s'en rapprochant et utilisant le langage Java, vous pouvez regarder du côté de &lt;a href="http://www.sparkjava.com/"&gt;Spark&lt;/a&gt;.&lt;br /&gt;
Et puis j'allais oublier, joyeux Noël à tous!&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://www.scalatra.org/"&gt;Site officiel de Scalatra&lt;/a&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/IUKF/~4/30yx2QgSebk" height="1" width="1"/&gt;</content><link rel="replies" type="text/html" href="http://coffeebean.loicdescotte.com/2011/12/premiers-pas-avec-scalatra.html#comment-form" title="0 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1231386620637429487/posts/default/3254262590656367937?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1231386620637429487/posts/default/3254262590656367937?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/IUKF/~3/30yx2QgSebk/premiers-pas-avec-scalatra.html" title="Premiers pas avec Scalatra" /><author><name>Loïc Descotte</name><uri>https://plus.google.com/117447657524839844765</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-vc8OSlrrAtM/AAAAAAAAAAI/AAAAAAAAFRA/sNj_WKeU-vI/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-vzAxLoQMZ18/Tvb0E0y7VKI/AAAAAAAADBA/I9RiutAx7ss/s72-c/scalatra_logo.png" height="72" width="72" /><thr:total>0</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://coffeebean.loicdescotte.com/2011/12/premiers-pas-avec-scalatra.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkUGRH88fSp7ImA9WhRSFE4.&quot;"><id>tag:blogger.com,1999:blog-1231386620637429487.post-1439490157246490642</id><published>2011-11-16T11:04:00.001+01:00</published><updated>2011-11-16T11:10:25.175+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-16T11:10:25.175+01:00</app:edited><title>Stateful VS Stateless : une mise en bouche du débat</title><content type="html">Philippe Charrière, Antoine Sabot-Durant et moi avons eu l’honneur d'être interviewés par les JDuchess pour présenter le sujet de la prochaine conférence du Lyon JUG : &lt;b&gt;Architecture stateful vs stateless &lt;/b&gt;(que nous animerons mardi prochain)&lt;br /&gt;
&lt;br /&gt;

Cette première partie du débat est &lt;a href="http://jduchess.org/duchess-france/blog/architecture-stateful-vs-stateless/"&gt;à lire ici&lt;/a&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/IUKF/~4/y4bqMRUVmVo" height="1" width="1"/&gt;</content><link rel="replies" type="text/html" href="http://coffeebean.loicdescotte.com/2011/11/stateful-vs-stateless-une-mise-en.html#comment-form" title="0 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1231386620637429487/posts/default/1439490157246490642?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1231386620637429487/posts/default/1439490157246490642?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/IUKF/~3/y4bqMRUVmVo/stateful-vs-stateless-une-mise-en.html" title="Stateful VS Stateless : une mise en bouche du débat" /><author><name>Loïc Descotte</name><uri>https://plus.google.com/117447657524839844765</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-vc8OSlrrAtM/AAAAAAAAAAI/AAAAAAAAFRA/sNj_WKeU-vI/s512-c/photo.jpg" /></author><thr:total>0</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://coffeebean.loicdescotte.com/2011/11/stateful-vs-stateless-une-mise-en.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0EARnszfSp7ImA9WhRSEU8.&quot;"><id>tag:blogger.com,1999:blog-1231386620637429487.post-4614479794822910225</id><published>2011-11-12T19:03:00.001+01:00</published><updated>2011-11-12T19:14:07.585+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-12T19:14:07.585+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Play" /><category scheme="http://www.blogger.com/atom/ns#" term="EJB" /><category scheme="http://www.blogger.com/atom/ns#" term="Stateless" /><category scheme="http://www.blogger.com/atom/ns#" term="JUG" /><category scheme="http://www.blogger.com/atom/ns#" term="Stateful" /><category scheme="http://www.blogger.com/atom/ns#" term="CDI" /><title>Présentation Stateful VS Stateless au Lyon JUG le 22 Novembre</title><content type="html">Le mardi 22 Novembre j'aurai l'honneur d'animer une session sur le thème des architectures stateless avec &lt;a href="http://www.k33g.org/"&gt;Philippe Charrière&lt;/a&gt;. Nous présenterons ce concept à travers une démo basée sur Play Framework.&lt;br /&gt;
&lt;br /&gt;
Nous confronterons notre vision à celle d'&lt;a href="http://www.linkedin.com/profile/view?id=987946&amp;amp;authType=name&amp;amp;authToken=tEXR&amp;amp;locale=en_US&amp;amp;pvs=pp&amp;amp;trk=ppro_viewmore"&gt;Antoine Sabot-Durant&lt;/a&gt; qui présentera l'alternative stateful avec Java EE (CDI, EJB 3...).&lt;br /&gt;
&lt;br /&gt;
Pour vous inscrire à cette présentation, c'est ici : &lt;a href="http://www.lyonjug.org/evenements/architecture-stateful-vs-stateless"&gt;http://www.lyonjug.org/evenements/architecture-stateful-vs-stateless&lt;/a&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/IUKF/~4/kgbMq5AvAOA" height="1" width="1"/&gt;</content><link rel="replies" type="text/html" href="http://coffeebean.loicdescotte.com/2011/11/presentation-stateful-vs-stateless-au.html#comment-form" title="0 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1231386620637429487/posts/default/4614479794822910225?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1231386620637429487/posts/default/4614479794822910225?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/IUKF/~3/kgbMq5AvAOA/presentation-stateful-vs-stateless-au.html" title="Présentation Stateful VS Stateless au Lyon JUG le 22 Novembre" /><author><name>Loïc Descotte</name><uri>https://plus.google.com/117447657524839844765</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-vc8OSlrrAtM/AAAAAAAAAAI/AAAAAAAAFRA/sNj_WKeU-vI/s512-c/photo.jpg" /></author><thr:total>0</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://coffeebean.loicdescotte.com/2011/11/presentation-stateful-vs-stateless-au.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0UGR3Y9eyp7ImA9WhdUGEQ.&quot;"><id>tag:blogger.com,1999:blog-1231386620637429487.post-8889797478385023514</id><published>2011-10-06T12:00:00.001+02:00</published><updated>2011-10-06T12:00:26.863+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-10-06T12:00:26.863+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Play" /><title>Un nouveau site pour Play.Rules!</title><content type="html">Mon coéquipier Philippe (aussi connu sous le pseudo &lt;a href="http://www.twitter.com/k33g_org"&gt;@k33g_org&lt;/a&gt;) vient de mettre en ligne un superbe site Web pour notre ebook Play.Rules!&lt;br /&gt;
&lt;br /&gt;
Ce site permet de consulter en ligne les différents chapitres.&lt;br /&gt;
Il nous servira aussi à publier les news concernant le livre et son avancement.&lt;br /&gt;
&lt;br /&gt;
Voici donc une URL à bookmarker ;) &lt;a href="http://3monkeys.github.com/play.rules/"&gt;http://3monkeys.github.com/play.rules/&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Pour ce qui est des nouveaux chapitres, on est pas mal occupés en ce moment mais du contenu supplémentaire ne devrait pas tarder à se montrer!&lt;img src="http://feeds.feedburner.com/~r/blogspot/IUKF/~4/3DAgRQfDBag" height="1" width="1"/&gt;</content><link rel="replies" type="text/html" href="http://coffeebean.loicdescotte.com/2011/10/un-nouveau-site-pour-playrules.html#comment-form" title="8 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1231386620637429487/posts/default/8889797478385023514?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1231386620637429487/posts/default/8889797478385023514?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/IUKF/~3/3DAgRQfDBag/un-nouveau-site-pour-playrules.html" title="Un nouveau site pour Play.Rules!" /><author><name>Loïc Descotte</name><uri>https://plus.google.com/117447657524839844765</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-vc8OSlrrAtM/AAAAAAAAAAI/AAAAAAAAFRA/sNj_WKeU-vI/s512-c/photo.jpg" /></author><thr:total>8</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://coffeebean.loicdescotte.com/2011/10/un-nouveau-site-pour-playrules.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0MFRnk6cSp7ImA9WhdVGUs.&quot;"><id>tag:blogger.com,1999:blog-1231386620637429487.post-3540463336227996474</id><published>2011-09-25T18:33:00.000+02:00</published><updated>2011-09-25T18:50:17.719+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-09-25T18:50:17.719+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Play" /><category scheme="http://www.blogger.com/atom/ns#" term="Livres" /><title>Play Framework Cookbook</title><content type="html">J'ai eu la chance de recevoir un exemplaire gratuit du livre Play

Framework Cookbook de la part de Packt en échange d'une critique sur

ce blog. Je vais donc essayer de vous donner mon avis tout en restant le plus objectif possible.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="https://www.packtpub.com/sites/default/files/imagecache/productview/5528OS_Play%20Framework%20Cookbook_Frontcover.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="https://www.packtpub.com/sites/default/files/imagecache/productview/5528OS_Play%20Framework%20Cookbook_Frontcover.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Après un premier chapitre qui présente toutes les opérations courantes d’un projet Play (création de vues, modèles, routes, gestion de la session utilisateur...), le livre se focalise sur un ensemble d’astuces répondant à des cas concrets. On trouve par exemple des chapitres traitant de (au hasard et dans le désordre) :&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;la configuration des routes par annotations&amp;nbsp;&lt;/li&gt;
&lt;li&gt;le caching&amp;nbsp;&lt;/li&gt;
&lt;li&gt;la génération de fichiers PDF ou de graphiques avec Google Chart API&amp;nbsp;&lt;/li&gt;
&lt;li&gt;l’injection de beans Spring ou Guice&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
Le livre explique en détail les principes de la création de modules Play et donne des exemples d’utilisation de modules existants, comme la connexion à une base NoSQL à l’aide du module MongoDB.&lt;br /&gt;
Si on devait résumer le style d’écriture, ce serait “beaucoup de code et peu de blala”.&lt;br /&gt;
Pour chaque partie on retrouve les mêmes sections : &lt;i&gt;getting ready, how to do it, how it works, there is more.

&lt;/i&gt;&lt;br /&gt;
Cette structure permet de comprendre en détail le fonctionnement des différentes briques du framework. La dernière de ces 3 parties a un rôle d’ouverture, on y trouve des conseils pour améliorer notre code ou pour booster les perfs ainsi que des solutions alternatives en s’appuyant par exemple sur des librairies externes.&lt;br /&gt;
&lt;br /&gt;
Le livre ne s’arrête pas au développement d’une application Play. Il présente un certain nombre d’astuces pour la mise en production (comme la mise en place d’un load balancer), l’intégration continue (avec jenkins), la gestion des logs ou encore le paramétrage d’un repository de modules privé.&lt;br /&gt;
Vous l'aurez compris, il couvre donc un scope d’astuces assez large. 

Ce livre ne demande pas forcément une lecture linéaire : on peut facilement sauter des chapitres pour aller directement chercher l’exemple qui répondra à notre problème du moment.&lt;br /&gt;
&lt;br /&gt;
Si on devait trouver quelques petits manques ou défauts, aucune plateforme de cloud n’est présentée. Le livre a été écrit trop tôt pour parler du PaaS Heroku, cependant les modules CloudBees et Google APP Engine existent depuis un certain temps et auraient pu être abordés.

Pas de Scala non plus, mais il est vrai cela demanderait presque un deuxième livre, l’API Play Scala étant vraiment différente de la version Java (ceci devrait changer avec Play 2.0).&lt;br /&gt;
Enfin, le livre s'adresse plutôt aux personnes qui connaissent les bases de Play et qui veulent des recettes pour répondre a des problèmes précis. Cette démarche va assez loin puisque le livre comprend  même une partie dédiée à l’optimisation de byte code. En ce sens, le tutoriel YABE de la documentation officielle ou le livre Play.Rules (pub perso ;) seront sûrement  des pistes à privilégier pour les novices.&lt;br /&gt;
Cet ouvrage sera par contre une mine d’or pour les développeurs qui se lancent dans un projet “real life” et qui cherchent un vrai cookbook avec des techniques applicables au quotidien.

Et comme je suis sympa je vous offre &lt;a href="http://www.packtpub.com/sites/default/files/5528OS-Chapter-2-Using-Controllers.pdf?utm_source=packtpub&amp;amp;utm_medium=free&amp;amp;utm_campaign=pdf"&gt;un chapitre gratuit&lt;/a&gt;!&lt;img src="http://feeds.feedburner.com/~r/blogspot/IUKF/~4/fZjPYYXKRvE" height="1" width="1"/&gt;</content><link rel="replies" type="text/html" href="http://coffeebean.loicdescotte.com/2011/09/play-framework-cookbook.html#comment-form" title="0 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1231386620637429487/posts/default/3540463336227996474?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1231386620637429487/posts/default/3540463336227996474?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/IUKF/~3/fZjPYYXKRvE/play-framework-cookbook.html" title="Play Framework Cookbook" /><author><name>Loïc Descotte</name><uri>https://plus.google.com/117447657524839844765</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-vc8OSlrrAtM/AAAAAAAAAAI/AAAAAAAAFRA/sNj_WKeU-vI/s512-c/photo.jpg" /></author><thr:total>0</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://coffeebean.loicdescotte.com/2011/09/play-framework-cookbook.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Ck8AQ30_eCp7ImA9WhdWF04.&quot;"><id>tag:blogger.com,1999:blog-1231386620637429487.post-6545668427855466200</id><published>2011-08-29T19:06:00.000+02:00</published><updated>2011-09-11T10:47:22.340+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-09-11T10:47:22.340+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Play" /><category scheme="http://www.blogger.com/atom/ns#" term="Cloud" /><category scheme="http://www.blogger.com/atom/ns#" term="Heroku" /><title>Heroku offre un PaaS pour Play Framework</title><content type="html">Bonne nouvelle les amis, la plateforme de Cloud Heroku, particulièrement célèbre dans le monde Ruby, &lt;a href="http://blog.heroku.com/archives/2011/8/29/play/"&gt;vient d'annoncer&lt;/a&gt; un support natif des application Play Framework!&lt;br /&gt;
&lt;br /&gt;
Nous avons donc à notre disposition un PaaS pour notre (ou du moins mon) framework préféré, permettant de déployer une application en production en une ligne commande (via Git).&lt;br /&gt;
De plus, en dessous d'un certaine nombre d'un certain nombre de connexions le service est gratuit.&lt;br /&gt;
Et si votre application rencontre le succès que vous espériez, vous pourrez alors passer sur du payant avec une configuration un peu plus costaud et bénéficier de toute la scalabilité offerte par la plateforme.&lt;br /&gt;
&lt;br /&gt;
Tout ça pour vous dire que je pensais justement faire un chapitre dans l'eBook &lt;a href="https://github.com/3monkeys/play.rules"&gt;play!rules&lt;/a&gt; sur le déploiement d'une application dans le Cloud... Heroku étant la première plateforme à supporter Play nativement, &amp;nbsp;je vais naturellement m'orienter vers cette solution. &amp;nbsp;So stay tuned, le chapitre devrait arriver très rapidement.&lt;br /&gt;
&lt;br /&gt;
Ps : merci à Nicolas du &lt;a href="http://www.touilleur-express.fr/"&gt;Touilleur Express&lt;/a&gt; qui a tweeté cette information hyper vite comme toujours!&lt;br /&gt;
&lt;br /&gt;
MAJ : Le (très court) chapitre sur Heroku est maintenant disponible &lt;a href="https://github.com/3monkeys/play.rules/blob/master/livre/part01-je-suis-pret/ch06-deploiement-dans-le-cloud.md"&gt;ici&lt;/a&gt;.&lt;img src="http://feeds.feedburner.com/~r/blogspot/IUKF/~4/cE12qLSIRB0" height="1" width="1"/&gt;</content><link rel="replies" type="text/html" href="http://coffeebean.loicdescotte.com/2011/08/play-framework-heroku-bientot-dans.html#comment-form" title="2 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1231386620637429487/posts/default/6545668427855466200?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1231386620637429487/posts/default/6545668427855466200?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/IUKF/~3/cE12qLSIRB0/play-framework-heroku-bientot-dans.html" title="Heroku offre un PaaS pour Play Framework" /><author><name>Loïc Descotte</name><uri>https://plus.google.com/117447657524839844765</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-vc8OSlrrAtM/AAAAAAAAAAI/AAAAAAAAFRA/sNj_WKeU-vI/s512-c/photo.jpg" /></author><thr:total>2</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://coffeebean.loicdescotte.com/2011/08/play-framework-heroku-bientot-dans.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUQEQ348fSp7ImA9WhRUGEg.&quot;"><id>tag:blogger.com,1999:blog-1231386620637429487.post-1242925440717957397</id><published>2011-07-20T12:12:00.009+02:00</published><updated>2012-01-29T17:08:22.075+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-29T17:08:22.075+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Scala" /><category scheme="http://www.blogger.com/atom/ns#" term="Jetbrains" /><category scheme="http://www.blogger.com/atom/ns#" term="Kotlin" /><category scheme="http://www.blogger.com/atom/ns#" term="IDEA" /><category scheme="http://www.blogger.com/atom/ns#" term="Groovy" /><category scheme="http://www.blogger.com/atom/ns#" term="JVM" /><title>Kotlin: un nouveau langage pour la JVM</title><content type="html">JetBrains (l'éditeur de l'excellent IDE IntelliJ IDEA) vient d'annoncer qu'ils lançaient leur propre langage pour la JVM : Kotlin.&lt;br /&gt;
Cette annonce arrive quelques mois après celle de Red Hat qui a presénté le langage Ceylon au mois d'Avril.&lt;br /&gt;
&lt;br /&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;
Alors à quoi ressemble ce nouveau langage? Pour faire court, prenez Scala, rendez le un peu plus abordable et facile d'accès, ajoutez y un peu de Groovy et quelques nouvelles features. &lt;br /&gt;
&lt;br /&gt;
Vous comprendrez mieux avec quelques exemples de code .&lt;br /&gt;
&lt;br /&gt;
On peut facilement écrire ce genre de code grâce aux expressions lambda :&lt;br /&gt;
&lt;pre class="java" name="code"&gt;names filter {it.startsWith("A")} map {it.toUpperCase()} foreach {print(it)}
&lt;/pre&gt;
&lt;br /&gt;
Ce code écrit en majuscule dans la console tous les nom commençant par A.&lt;br /&gt;
C'est le genre de choses toutes simples qui peuvent être vraiment lourdes à écrire en Java...&lt;br /&gt;
&lt;br /&gt;
On peut également faire du pattern matching à la Scala :&lt;br /&gt;
&lt;pre class="java" name="code"&gt;fun cases(obj : Any) {
  when(obj) {
    1          =&amp;gt; print("One")
    "Hello"    =&amp;gt; print("Greeting")
    is Long    =&amp;gt; print("Long")
    !is String =&amp;gt; print("Not a string")
    else       =&amp;gt; print("Unknown") 
  }
}
&lt;/pre&gt;
&lt;br /&gt;
Kotlin est un langage à typage statique. Mais il propose un mécanisme d'inférence de type pour alléger la syntaxe : &lt;br /&gt;
&lt;pre class="java" name="code"&gt;var a : Int = 1
var b = 1 // Type inféré
&lt;/pre&gt;
&lt;br /&gt;
On peut même automatiser les cast dans certains cas :&lt;br /&gt;
&lt;pre class="java" name="code"&gt;if (obj is String) 
    return obj.length // pas de cast explicite 
&lt;/pre&gt;
&lt;br /&gt;
Le langage fournit un système de properties très bien pensé (pour éviter d'écrire les getters et setters à la main), qui rappelle un peu celui de C#.  &lt;br /&gt;
&lt;br /&gt;
La gestion des null est aussi très efficace et devrait résoudre pas mal de problèmes liés au null pointers. Un champ ne peut être null que si on l'autorise :&lt;br /&gt;
&lt;pre class="java" name="code"&gt;var a : String = "abc"
a = null // erreur de compilation

var b : String? = "abc"
b = null // ok
&lt;/pre&gt;
&lt;br /&gt;
Pour y accéder, on fait comme en Groovy :&lt;br /&gt;
&lt;pre class="java" name="code"&gt;b?.length() 
&lt;/pre&gt;
&lt;br /&gt;
Ceci renverra length() si b est non null, rien sinon. On pourra donc éviter quelques fastidieux if(b!=null) dans notre code.&lt;br /&gt;
&lt;br /&gt;
Pour réduire le risque d'erreurs, l'utilisation du "?" est obligatoire pour accéder aux objets "nullables" :&lt;br /&gt;
&lt;pre class="java" name="code"&gt;b.length() //erreur de compilation
&lt;/pre&gt;
&lt;br /&gt;
Enfin, le langage offre la même sécurité que Scala au niveau de l'immutabilité, avec l'usage du mot clé "val" (au lieu de "var") pour déclarer une propriété immuable. Ceci aura aussi une incidence sur la génération automatique des accesseurs : seul un getter est généré pour une propriété de type val. &lt;br /&gt;
&lt;br /&gt;
Si cette mise en bouche vous a ouvert l'appétit, je vous conseille de regarder &lt;a href="http://confluence.jetbrains.net/display/Kotlin/Examples"&gt;ces exemples plus détaillés&lt;/a&gt; sur le site du langage.&lt;br /&gt;
&lt;br /&gt;
En tout cas personnellement je trouve ça très prometteur. Le support natif dans IntelliJ IDEA sera un gros plus des son lancement. J'espère sincèrement que ce langage aura sa chance dans la jungle des langages pour la JVM!
&lt;br /&gt;
&lt;br /&gt;
MAJ : Vous pouvez dès à présent &lt;a href="https://plus.google.com/117447657524839844765/posts/TKtXXRYcu2Z"&gt;jouer avec la Web demo&lt;/a&gt; de Kotlin&lt;img src="http://feeds.feedburner.com/~r/blogspot/IUKF/~4/2WxItKRknsk" height="1" width="1"/&gt;</content><link rel="replies" type="text/html" href="http://coffeebean.loicdescotte.com/2011/07/kotlin-un-nouveau-langage-pour-la-jvm.html#comment-form" title="0 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1231386620637429487/posts/default/1242925440717957397?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1231386620637429487/posts/default/1242925440717957397?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/IUKF/~3/2WxItKRknsk/kotlin-un-nouveau-langage-pour-la-jvm.html" title="Kotlin: un nouveau langage pour la JVM" /><author><name>Loïc Descotte</name><uri>https://plus.google.com/117447657524839844765</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-vc8OSlrrAtM/AAAAAAAAAAI/AAAAAAAAFRA/sNj_WKeU-vI/s512-c/photo.jpg" /></author><thr:total>0</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://coffeebean.loicdescotte.com/2011/07/kotlin-un-nouveau-langage-pour-la-jvm.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0EAQno9eip7ImA9WhVWGEU.&quot;"><id>tag:blogger.com,1999:blog-1231386620637429487.post-7116988539350904392</id><published>2011-06-24T22:34:00.000+02:00</published><updated>2012-05-01T18:27:23.462+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-05-01T18:27:23.462+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Scala" /><category scheme="http://www.blogger.com/atom/ns#" term="Play" /><category scheme="http://www.blogger.com/atom/ns#" term="Apprendre_Play" /><title>Play!Rules: un chapitre sur Play et Scala</title><content type="html">Un nouveau chapitre est disponible dans l'ebook gratuit&amp;nbsp;(et open source)&amp;nbsp;Play!Rules, il explique comment développer avec Play Framework et le langage Scala .&lt;br /&gt;
&lt;br /&gt;
Pour en savoir plus, &lt;a href="https://github.com/3monkeys/play.rules/blob/master/livre.play.un/part02-ch02-play-et-scala.md"&gt;ça se passe ici&lt;/a&gt;.&lt;img src="http://feeds.feedburner.com/~r/blogspot/IUKF/~4/EfnrI4khSb8" height="1" width="1"/&gt;</content><link rel="replies" type="text/html" href="http://coffeebean.loicdescotte.com/2011/06/playrules-un-chapitre-sur-play-et-scala.html#comment-form" title="2 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1231386620637429487/posts/default/7116988539350904392?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1231386620637429487/posts/default/7116988539350904392?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/IUKF/~3/EfnrI4khSb8/playrules-un-chapitre-sur-play-et-scala.html" title="Play!Rules: un chapitre sur Play et Scala" /><author><name>Loïc Descotte</name><uri>https://plus.google.com/117447657524839844765</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-vc8OSlrrAtM/AAAAAAAAAAI/AAAAAAAAFRA/sNj_WKeU-vI/s512-c/photo.jpg" /></author><thr:total>2</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://coffeebean.loicdescotte.com/2011/06/playrules-un-chapitre-sur-play-et-scala.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUMAQX04eip7ImA9WhRQF0Q.&quot;"><id>tag:blogger.com,1999:blog-1231386620637429487.post-8300956857116083102</id><published>2011-05-28T10:50:00.021+02:00</published><updated>2011-12-13T17:24:00.332+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-13T17:24:00.332+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="DDD" /><category scheme="http://www.blogger.com/atom/ns#" term="QueryDSL" /><category scheme="http://www.blogger.com/atom/ns#" term="Spring" /><title>Spring Data JPA et Querydsl</title><content type="html">SpringSource a récemment lancé le projet Spring-Data, un ensemble de sous projets ayant pour but de nous aider à manipuler plus facilement nos données.&lt;br /&gt;
&lt;br /&gt;
Nous allons nous attarder sur Spring-Data-JPA, qui fournit un ensemble d'automatisations pour JPA.&lt;br /&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: large;"&gt;&lt;b&gt;Repositories&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Les repositories sont des interfaces pour lesquelles nous n'avons pas à fournir d'implémentation. Ces interfaces seront implémentées par le framework lui même au démarrage du contexte Spring.&lt;br /&gt;
&lt;br /&gt;
On considère la classe Person :&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="java" name="code"&gt;@Entity
public class Person {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String firstName;
    private String lastName;
    private Integer age;
    private String city;
 //getters &amp;amp; setters 
}
&lt;/pre&gt;
&lt;br /&gt;
Si on écrit par exemple : &lt;br /&gt;
&lt;br /&gt;
&lt;pre class="java" name="code"&gt;public interface PersonRepository extends JpaRepository&amp;lt;Person, Long&amp;gt; {
    List&amp;lt;Person&amp;gt; findByCity(String city);    
}
&lt;/pre&gt;
&lt;br /&gt;
Spring implémentera une requête en se basant sur le nom de la méthode, pour rechercher des personnes par la ville où elles habitent.&lt;br /&gt;
&lt;br /&gt;
Pour utiliser plusieurs paramètres on utilise le mot clé "And" :&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="java" name="code"&gt;List&amp;lt;Person&amp;gt; findByFirstNameAndLastName(String firstName, String lastName);
&lt;/pre&gt;
&lt;br /&gt;
On peut utiliser tout un tas d'autres mots clés dans le nom des méthodes pour construire nos requêtes :&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;And&lt;/li&gt;
&lt;li&gt;Or&lt;/li&gt;
&lt;li&gt;GreaterThan&lt;/li&gt;
&lt;li&gt;LessThan&lt;/li&gt;
&lt;li&gt;Like&lt;/li&gt;
&lt;li&gt;IsNull&lt;/li&gt;
&lt;li&gt;OrderBy&lt;/li&gt;
&lt;li&gt;...&lt;/li&gt;
&lt;/ul&gt;
Par exemple :&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="java" name="code"&gt;List&amp;lt;Person&amp;gt; findByAgeOrderByLastnameDesc(Integer age);
&lt;/pre&gt;
&lt;br /&gt;
Les repositories permettent aussi de persister les entités dans la base :&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="java" name="code"&gt;personRepository.save(person);
&lt;/pre&gt;
&lt;br /&gt;
Ces fonctionnalités sont directement reprises depuis Hades, les 2 frameworks partageant le même spec leader.&lt;br /&gt;
&lt;br /&gt;
Si on veut écrire directement une requête JPQL, on peut utiliser l'annotation @Query :&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="java" name="code"&gt;@Query("ma super requête ici")
List&amp;lt;Person&amp;gt; findWithMyCustomQuery(Customer customer);
&lt;/pre&gt;
&lt;br /&gt;
La requête sera exécutée lorsque qu'on appellera la méthode findWithMyCustomQuery.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Named queries&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Pour utiliser une NamedQuery, il suffit que le nom de la méthode du repository suive le même nom que la NamedQuery. Dans ce cas de figure, le framework n'essaiera pas de générer une requête en suivant le nom de la méthode.&lt;br /&gt;
Par exemple la méthode findByNameWithMyFilters sera mappée sur la requête nommée "Person.findByNameWithMyFilters". &lt;br /&gt;
&lt;br /&gt;
Entité : 

&lt;br /&gt;
&lt;pre class="java" name="code"&gt;@Entity
@NamedQuery(name = "Person.findByNameWithMyFilters", 
  query = "select p from Person p where filter1 = ? and filter2 = ?")
public class Person {...}
&lt;/pre&gt;
&lt;br /&gt;
Repository : 

&lt;br /&gt;
&lt;pre class="java" name="code"&gt;Person findByNameWithMyFilters(String filter1, String filter2);
&lt;/pre&gt;
&amp;nbsp; &lt;br /&gt;
&lt;br /&gt;
Ces repositories nous facilitent bien la vie en générant pour nous les requêtes pour un grand nombre de cas courants. Un détail qui a son importance : toutes les méthodes des repositories sont transactionnelles par défaut.&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: large;"&gt;&lt;b&gt;Querydsl&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Querydsl est une librairie qui apporte des API pour requêter des entités de manière "typesafe" et avec une syntaxe épurée. Spring-Data supporte cette librairie pour simplifier l'écriture de prédicats en Java.&lt;br /&gt;
&lt;br /&gt;
Voici quelques exemples de requêtes, avec l'utilisation des mots clés eq (equals), like et gt (greater than) :&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="java" name="code"&gt;private static QPerson person = QPerson.person;

public static BooleanExpression fromCity(String city) {
 return person.city.like(city);
}

public static BooleanExpression byName(String firstName, String lastName) {
 return person.firstName.eq(firstName).and(person.lastName.eq(lastName));
}

public static BooleanExpression adults() {
 return person.age.gt(18);
}
&lt;/pre&gt;
&lt;br /&gt;
J'aime beaucoup cette syntaxe, elle est vraiment fluide, facile à écrire et lisible. Il est bien sur possible de gérer des cas plus complexes, je vous laisse consulter &lt;a href="http://blog.mysema.com/2010/07/querying-hibernate-with-querydsl.html"&gt;la doc de Querydsl&lt;/a&gt; pour en savoir plus.&lt;br /&gt;
&lt;br /&gt;
Pour&amp;nbsp;exécuter une requête utilisant un de ces prédicats, il suffit d'écrire :&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="java" name="code"&gt;personRepository.findAll(Person.fromCity("maVille"))
&lt;/pre&gt;
&lt;br /&gt;
ou&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="java" name="code"&gt;personRepository.findAll(Person.adults())
&lt;/pre&gt;
&lt;br /&gt;
Pour que tout cela fonctionne, notre repository doit implémenter QuerydslPredicateExecutor&lt;person&gt;. On doit également définir ce plugin dans le build maven, qui se chargera des générer les classes Q* pour chacune des entités du projet :&lt;br /&gt;
&lt;br /&gt;
&lt;/person&gt;&lt;br /&gt;
&lt;pre class="xml" name="code"&gt;&amp;lt;plugin&amp;gt;
        &amp;lt;groupId&amp;gt;com.mysema.maven&amp;lt;/groupId&amp;gt;
      &amp;lt;artifactId&amp;gt;maven-apt-plugin&amp;lt;/artifactId&amp;gt;
      &amp;lt;version&amp;gt;1.0&amp;lt;/version&amp;gt;
      &amp;lt;executions&amp;gt;
          &amp;lt;execution&amp;gt;
              &amp;lt;phase&amp;gt;generate-sources&amp;lt;/phase&amp;gt;
              &amp;lt;goals&amp;gt;
                  &amp;lt;goal&amp;gt;process&amp;lt;/goal&amp;gt;
              &amp;lt;/goals&amp;gt;
              &amp;lt;configuration&amp;gt;
                  &amp;lt;outputDirectory&amp;gt;target/generated-sources&amp;lt;/outputDirectory&amp;gt;
                  &amp;lt;processor&amp;gt;com.mysema.query.apt.jpa.JPAAnnotationProcessor&amp;lt;/processor&amp;gt;
              &amp;lt;/configuration&amp;gt;
          &amp;lt;/execution&amp;gt;
      &amp;lt;/executions&amp;gt;
  &amp;lt;/plugin&amp;gt;
&lt;/pre&gt;
&lt;br /&gt;
N.B : Il est possible d'écrire nos prédicats avec l'api criteria de JPA 2 au lieu de Querydsl si on le souhaite, en utilisant la classe org.springframework.data.jpa.domain.Specification à la place de nos BooleanExpression.&lt;br /&gt;
&lt;br /&gt;
Voyons comment utiliser nos repositories et nos prédicats :&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="java" name="code"&gt;@Test
  public void testPersistence() {

      Person p = new Person();
      p.setFirstName("loic");
      p.setLastName("descotte");
      p.setCity("Grenoble");
      p.setAge(29);

      Person p2 = new Person();
      p2.setFirstName("john");
      p2.setLastName("doe");
      p2.setAge(17);
      p2.setCity("NYC");

      //save
      personRepository.save(p);
      personRepository.save(p2);

      persons = personRepository.findAll();
      assertEquals(persons.size(),2);

      persons = (List) personRepository.findAll(Person.fromCity("%Gre%"));
      assertEquals(persons.size(),1);
      assertEquals(persons.get(0).getFirstName(),"loic");

      persons = (List) personRepository.findByFirstNameAndLastName("loic", "descotte");
      assertEquals(persons.size(),1);
      assertEquals(persons.get(0).getCity(),"Grenoble");

      persons = (List) personRepository.findAll(Person.adults());
      assertEquals(persons.size(),1);
      assertEquals(persons.get(0).getFirstName(),"loic");
  }

&lt;/pre&gt;
&lt;br /&gt;
Dans cet exemple le code client est une classe de test, mais on peut très bien appeler notre repository depuis un service REST, depuis la couche graphique, etc. (voir le code source de l'exemple en téléchargement à la fin de cet article).&lt;br /&gt;
&lt;br /&gt;
On voit dans ces exemples qu'on a complètement modifié notre façon d'architecturer notre application Spring: on peut si on le souhaite se passer des couche "services" ou "business" qui contiennent habituellement la logique de notre application.  &lt;br /&gt;
En effet Spring-Data et ses repositories ont un bon gout de DDD (Domain Driven Design). Ceux qui ont essayé Play connaissent déjà cette approche.&lt;br /&gt;
Le code métier de notre application peut être recentré sur le modèle (objets du domaine métier). A nous la vrai conception objet, fini les modèles anémiques sans intelligence dont les seules méthodes sont des getters et des setters. &lt;br /&gt;
Comme vous le voyez dans cet exemple, on a même la possibilité de placer nos prédicats d'accès à la base de données dans la classe Personne. &lt;br /&gt;
&lt;br /&gt;
Pour conclure ce nouveau framework est vraiment prometteur et apporte pas mal de nouveautés et de facilités aux applications codées en environnement Spring. &lt;br /&gt;
Le seul bémol que j'ai vu étant (comme souvent avec Spring et Maven) le temps nécessaire pour mettre au point la configuration XML et trouver les bonnes dépendances (sans compter les conflits avec Jersey, etc.)&lt;br /&gt;
Mais comme je suis sympa vous pouvez tout recopier dans le code source des exemples de l'article : &lt;a href="http://dl.dropbox.com/u/7549438/blog/Directory.zip"&gt;code source de l'exemple&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Je vous conseille de jeter également un oeil aux autres projets de &lt;a href="http://www.springsource.org/spring-data"&gt;Spring-Data&lt;/a&gt;, tout aussi intéressants et qui adressent le monde NoSQL (bases orientées graphes, documents, clé/valeur...).&lt;img src="http://feeds.feedburner.com/~r/blogspot/IUKF/~4/NGgVdn5UDCc" height="1" width="1"/&gt;</content><link rel="replies" type="text/html" href="http://coffeebean.loicdescotte.com/2011/05/spring-data-jpa-et-querydsl.html#comment-form" title="13 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1231386620637429487/posts/default/8300956857116083102?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1231386620637429487/posts/default/8300956857116083102?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/IUKF/~3/NGgVdn5UDCc/spring-data-jpa-et-querydsl.html" title="Spring Data JPA et Querydsl" /><author><name>Loïc Descotte</name><uri>https://plus.google.com/117447657524839844765</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-vc8OSlrrAtM/AAAAAAAAAAI/AAAAAAAAFRA/sNj_WKeU-vI/s512-c/photo.jpg" /></author><thr:total>13</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://coffeebean.loicdescotte.com/2011/05/spring-data-jpa-et-querydsl.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0UAQ34zfyp7ImA9WhVWGEQ.&quot;"><id>tag:blogger.com,1999:blog-1231386620637429487.post-4057024695464829565</id><published>2011-05-22T16:33:00.002+02:00</published><updated>2012-05-01T18:54:02.087+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-05-01T18:54:02.087+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Play" /><category scheme="http://www.blogger.com/atom/ns#" term="Apprendre_Play" /><category scheme="http://www.blogger.com/atom/ns#" term="HTML5" /><category scheme="http://www.blogger.com/atom/ns#" term="WebSocket" /><title>WebSocket et Play Framework</title><content type="html">Vous avez surement entendu parler de WebSocket, un (futur) standard HTML 5 qui permet de faire du push de données du serveur vers le navigateur.&lt;br /&gt;
L'utilisation des WebSockets est très simple avec Play et très utile dans le cas de traitements asynchrones.&lt;br /&gt;
&lt;br /&gt;
Vous pouvez lire ce nouveau chapitre dédié à WebSocket sur l'ebook play.rules :&amp;nbsp;&lt;a href="https://github.com/3monkeys/play.rules/blob/master/livre.play.un/part01-ch05-jobs-et-traitements-asynchrones.md"&gt;https://github.com/3monkeys/play.rules/blob/master/livre.play.un/part01-ch05-jobs-et-traitements-asynchrones.md&lt;/a&gt;&amp;nbsp;(deuxième partie du fichier).&lt;br /&gt;
&lt;br /&gt;
Comme d'habitude n'hésitez pas à envoyer vos remarques si des éléments ne sont pas clairs ou si vous trouvez des fautes :)&lt;img src="http://feeds.feedburner.com/~r/blogspot/IUKF/~4/lGiw-lfmMX8" height="1" width="1"/&gt;</content><link rel="replies" type="text/html" href="http://coffeebean.loicdescotte.com/2011/05/websocket-et-play-framework.html#comment-form" title="5 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1231386620637429487/posts/default/4057024695464829565?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1231386620637429487/posts/default/4057024695464829565?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/IUKF/~3/lGiw-lfmMX8/websocket-et-play-framework.html" title="WebSocket et Play Framework" /><author><name>Loïc Descotte</name><uri>https://plus.google.com/117447657524839844765</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-vc8OSlrrAtM/AAAAAAAAAAI/AAAAAAAAFRA/sNj_WKeU-vI/s512-c/photo.jpg" /></author><thr:total>5</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://coffeebean.loicdescotte.com/2011/05/websocket-et-play-framework.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D04DR3o7eCp7ImA9WhdWEk4.&quot;"><id>tag:blogger.com,1999:blog-1231386620637429487.post-8974841571866611416</id><published>2011-04-12T19:25:00.001+02:00</published><updated>2011-09-05T17:19:36.400+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-09-05T17:19:36.400+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Scala" /><category scheme="http://www.blogger.com/atom/ns#" term="Play" /><category scheme="http://www.blogger.com/atom/ns#" term="Apprendre_Play" /><title>Du Play et du Scala!</title><content type="html">Je suis entrain de réécrire entièrement en Scala mon application de démo pour Play framework!&lt;br /&gt;
Le code de l'application est disponible ici :&amp;nbsp;&lt;a href="https://github.com/loicdescotte/vote4music-scala"&gt;https://github.com/loicdescotte/vote4music-scala&lt;/a&gt;&lt;br /&gt;
Une occasion de comparer les langages, puisque la version Java est disponible là :&amp;nbsp;&lt;a href="https://github.com/loicdescotte/vote4music"&gt;https://github.com/loicdescotte/vote4music&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Personnellement&amp;nbsp;je trouve l'API Scala de Play plutôt bien pensée, elle colle même peut être encore plus à l'esprit Play que la version Java. On gagne en concision et surtout en expressivité du code grâce à l'approche fonctionnelle.&lt;br /&gt;
&lt;br /&gt;
Le code de l'application n'est pas encore parfait, il reste quelques bugs et quelques&amp;nbsp;&lt;i&gt;TODO &lt;/i&gt;(les API Json et XML ne sont par exemple pas encore fonctionnelles). Mais la plupart des fonctionnalités sont là.&lt;br /&gt;
&lt;br /&gt;
Cette version Scala fera d'ailleurs l'objet d'un chapitre dans le livre &lt;a href="https://github.com/3monkeys/play.rules"&gt;Play.rules&lt;/a&gt;&amp;nbsp;dont je vous ai parlé dans le post précédent.&lt;img src="http://feeds.feedburner.com/~r/blogspot/IUKF/~4/4sJjji7lDcM" height="1" width="1"/&gt;</content><link rel="replies" type="text/html" href="http://coffeebean.loicdescotte.com/2011/04/du-play-et-du-scala.html#comment-form" title="6 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1231386620637429487/posts/default/8974841571866611416?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1231386620637429487/posts/default/8974841571866611416?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/IUKF/~3/4sJjji7lDcM/du-play-et-du-scala.html" title="Du Play et du Scala!" /><author><name>Loïc Descotte</name><uri>https://plus.google.com/117447657524839844765</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-vc8OSlrrAtM/AAAAAAAAAAI/AAAAAAAAFRA/sNj_WKeU-vI/s512-c/photo.jpg" /></author><thr:total>6</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://coffeebean.loicdescotte.com/2011/04/du-play-et-du-scala.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0EAQ3oycCp7ImA9WhdWEk4.&quot;"><id>tag:blogger.com,1999:blog-1231386620637429487.post-877466269928904449</id><published>2011-04-10T12:48:00.003+02:00</published><updated>2011-09-05T17:14:02.498+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-09-05T17:14:02.498+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Play" /><category scheme="http://www.blogger.com/atom/ns#" term="Apprendre_Play" /><title>Pourquoi Play + Ebook gratuit et open source!</title><content type="html">Sur ce blog il m'est souvent arrivé de vous parler de Play Framework.&lt;br /&gt;
Aujourd'hui&amp;nbsp;revenons un peu au début de l'histoire, je vais vous présenter les raisons pour lesquelles j'aime autant Play.&lt;br /&gt;
&lt;br /&gt;
&lt;a href="https://github.com/3monkeys/play.rules/blob/master/livre/02-Pourquoi-play.md"&gt;J'ai décris toutes ces raisons ici&lt;/a&gt;&amp;nbsp;(suivez le lien)&lt;br /&gt;
&lt;br /&gt;
En fait ceci n'est que le premier chapitre d'un Ebook gratuit, open source et collaboratif sur lequel je travaille avec mes 2 amis &lt;a href="http://www.twitter.com/k33g_org"&gt;@k33g_org&lt;/a&gt; et &lt;a href="http://www.twitter.com/mklabs"&gt;@mklabs&lt;/a&gt;! Notre but est de fournir un livre convivial,&amp;nbsp;facile&amp;nbsp;à lire et avec un ton un peu différent de ce qu'on trouve dans la littérature habituelle. L'aspect open source&amp;nbsp;donnera,&amp;nbsp;je l'espère, l'envie à des personnes de nous aider pour les relectures ou de&amp;nbsp;contribuer&amp;nbsp;à des chapitres!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;
On en est qu'a tout début, il reste encore beaucoup à écrire. Mais on avance à bon rythme et petit à petit le livre devrait se remplir! Vous pouvez&amp;nbsp;déjà&amp;nbsp;le consulter&amp;nbsp;librement sur GitHub :&amp;nbsp;&lt;a href="https://github.com/3monkeys/play.rules"&gt;https://github.com/3monkeys/play.rules&lt;/a&gt;&lt;/div&gt;
&lt;img src="http://feeds.feedburner.com/~r/blogspot/IUKF/~4/PdYab8JoLjI" height="1" width="1"/&gt;</content><link rel="replies" type="text/html" href="http://coffeebean.loicdescotte.com/2011/04/pourquoi-play-ebook-gratuit-et-open.html#comment-form" title="7 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1231386620637429487/posts/default/877466269928904449?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1231386620637429487/posts/default/877466269928904449?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/IUKF/~3/PdYab8JoLjI/pourquoi-play-ebook-gratuit-et-open.html" title="Pourquoi Play + Ebook gratuit et open source!" /><author><name>Loïc Descotte</name><uri>https://plus.google.com/117447657524839844765</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-vc8OSlrrAtM/AAAAAAAAAAI/AAAAAAAAFRA/sNj_WKeU-vI/s512-c/photo.jpg" /></author><thr:total>7</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://coffeebean.loicdescotte.com/2011/04/pourquoi-play-ebook-gratuit-et-open.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0UDQHY8eyp7ImA9WhZSEEg.&quot;"><id>tag:blogger.com,1999:blog-1231386620637429487.post-2549911136066772536</id><published>2011-03-25T14:21:00.000+01:00</published><updated>2011-03-25T14:21:11.873+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-25T14:21:11.873+01:00</app:edited><title>Présentation du langage Scala par Aleksandar Prokopec de l'EPFL</title><content type="html">Lundi dernier nous avons eu le plaisir d'accueillir à l'Alpes JUG&amp;nbsp;Aleksandar Prokopec, un des contributeurs de Scala, le langage orienté objet et fonctionnel pour la JVM dont tout le monde parle en ce moment.&lt;br /&gt;
&lt;br /&gt;
Les slides et le compte rendu de la présentation sont disponible &lt;a href="http://www.alpesjug.fr/?p=774"&gt;ici&lt;/a&gt;.&lt;img src="http://feeds.feedburner.com/~r/blogspot/IUKF/~4/WxzHZu-FDfM" height="1" width="1"/&gt;</content><link rel="replies" type="text/html" href="http://coffeebean.loicdescotte.com/2011/03/presentation-du-langage-scala-par.html#comment-form" title="0 commentaires" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1231386620637429487/posts/default/2549911136066772536?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1231386620637429487/posts/default/2549911136066772536?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/IUKF/~3/WxzHZu-FDfM/presentation-du-langage-scala-par.html" title="Présentation du langage Scala par Aleksandar Prokopec de l'EPFL" /><author><name>Loïc Descotte</name><uri>https://plus.google.com/117447657524839844765</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-vc8OSlrrAtM/AAAAAAAAAAI/AAAAAAAAFRA/sNj_WKeU-vI/s512-c/photo.jpg" /></author><thr:total>0</thr:total><gd:extendedProperty name="commentSource" value="1" /><gd:extendedProperty name="commentModerationMode" value="FILTERED_POSTMOD" /><feedburner:origLink>http://coffeebean.loicdescotte.com/2011/03/presentation-du-langage-scala-par.html</feedburner:origLink></entry></feed>
