Utilisation de Scala pour simplifier une application PrimeFaces + Cassandra

Suite à la publication de cette article, un deuxième billet a été publié, cette fois-ci en utilisant Groovy

Si vous avez suivi un peu l’actualité d’Ippon de ces derniers mois, vous avez dû constater qu’il y a deux technologies qui me plaisent particulièrement en ce moment :

  • PrimeFaces, une bibliothèque de composants JSF moderne et performante
  • Cassandra, une base de données NoSQL orientée colonne

Jusqu’à présent, et comme certainement 99% de la population de développeurs, j’utilisais ces technologies avec le langage Java. Cependant, la mode étant aux langages alternatifs, j’ai voulu faire un essai et utiliser Scala à la place de Java : je vais donc vous présenter ici cette application de test, et discuter des avantages et inconvénients rencontrés.

Préparation du jeu de test

L’application de test est un simple tableau JSF, affichant des données provenant d’une Column Family Cassandra.
Pour avoir cette Column Family fonctionnelle :

  1. Clonez notre repository Tatami : https://github.com/ippontech/tatami
  2. Dans une console, lancez Cassandra : “mvn cassandra:run”
  3. Dans une autre console, lancez Jetty : “mvn jetty:run”
  4. Vous pouvez maintenant utiliser Tatami en vous connectant sur http://127.0.0.1:8080 : créez quelques utilisateurs depuis la première page. Puisque nous n’avons pas configuré de serveur SMTP, vous verrez dans les logs de Tatami le mail envoyé, avec le mot de passe généré. Vous pourrez alors vous logger dans l’application pour indiquer votre nom et votre prénom.
  5. Eteignez votre serveur Jetty, car notre application Scala va utiliser le même port 8080

Mise en route de l’application : bienvenue dans le monde de SBT

SBT est l’outil de build “standard” que l’on utilise avec Scala. Sa principale force est de proposer une compilation incrémentale, ce qui permet de gagner beaucoup de temps : en effet, Scala est particulièrement lent à compiler, ce qui rend l’utilisation de Maven assez pénible.

Avec SBT on arrive ainsi à un processus de build acceptable, par contre c’est au détriment de tout le reste : les plugins SBT sont pour beaucoup buggés, mal documentés, et utilisent souvent de vieilles librairies. C’est pour cette raison que notre application va utiliser une vieille version de Jetty, avec uniquement la spécification Servlet 2.5, alors que notre objectif initial était d’utiliser TomEE et les spécifications CDI et Servlet 3.0.

Je trouve particulièrement dommage qu’un langage nous impose d’utiliser un outil de build, qui lui-même nous impose d’utiliser une vieille version de serveur d’application. Il y a là un signe sur l’état de la communauté Scala aujourd’hui : il y a peu de gens utilisant un serveur d’application Java EE avec Scala, la plupart préférant sans doute Akka/Play!

Pour pouvoir construire notre projet :

  1. Clonez notre repository https://github.com/ippontech/primefaces-scala-cassandra
  2. Installez SBT https://github.com/harrah/xsbt/wiki
  3. Lancez SBT et tapez : “container:start”
  4. L’application doit être disponible sur http://127.0.0.1:8080

Quelques astuces d’utilisation de SBT :

  1. Pour avoir un redéployement à chaud de l’application, tapez : “~;container:start; container:reload /”
  2. Pour pouvoir utiliser votre application dans IDEA, tapez : “gen-idea”

Bien entendu, je vous conseille fortement d’utiliser les plugins proposés sous Eclipse et IDEA afin de pouvoir faire du Scala.

Utilisation de Scala avec PrimeFaces

L’utilisation de classes Scala dans PrimeFaces est particulièrement simple. La classe User ne fait que quelques lignes :

(Code d’origine disponible ici)

C’est une “case class”: ce type de classe exporte automatiquement les paramètres de son constructeur, et génère automatiquement les méthodes equals() et toString(), ce qui facilite son écriture. De plus, cette classe utilise les annotations @BeanProperty afin de générer automatiquement les getters/setters correspondant à ces paramètres. Nous pouvons donc coder une classe extrêmement concise et lisible. Afin de pouvoir accéder à cette classe en JSF, nous avons besoin d’un ManagedBean, c’est-à-dire d’un Bean géré par JSF :

(Code d’origine disponible ici)

Cette classe est également extrêmement simple :

  • L’annotation @ManagedBean transforme automatiquement cette classe en composant géré par JSF (notez que dans le fichier web.xml le package de cette classe est scanné par JSF)
  • Elle utilise également le système des @BeanProperty pour générer des getters/setters
  • Attention cependant, cette classe n’utilise pas les collections Scala, qui ne sont pas compatibles avec les collections Java : nous renvoyons donc une collection Java, qui est le seul type d’objet que peut utiliser PrimeFaces

Cette classe sera par la suite utilisée normalement dans notre page JSF, disponible ici.

Utilisation de Scala avec Cassandra

Malheureusement, les drivers Cassandra disponibles en Scala ne sont pas de très bonne qualité :

  • Cassie, utilisé et développé par Twitter, semble le plus prometteur : malheureusement, à l’heure actuelle, le package n’est pas utilisable car il manque des dépendances. De plus, il n’est même pas listé dans la liste des drivers de Cassandra
  • Cascal est actuellement le plus abouti, mais son auteur d’origine a abandonné le projet

Cependant, cela n’est pas très important : Scala permet d’utiliser sans problème des librairies Java “normales”, il n’est donc pas nécessaire d’utiliser des librairies spécifiques à Scala.

J’ai donc simplement utilisé l’excellente librairie Hector que nous utilisons également sur Tatami, ce qui a fonctionné sans problème.

Voici le code d’accès à Cassandra, afin de lire l’ensemble des utilisateurs de la Column Family “User” :

(Code d’origine disponible ici)

Cette classe est intéressante à plusieurs niveaux :

  • Le code d’Hector est généralement assez complexe à utiliser car il utilise beaucoup les generics : Scala typant automatiquement les objets, il est nettement plus simple d’écrire “val rows” que d’écrire “List rows” ! Là encore, nous avons gagné beaucoup de temps à écrire ce code.
  • Cette classe est en fait un “object” Scala, ce qui en fait automatiquement un singleton. Pas la peine de faire des méthodes static (qui n’existent pas en Scala, d’ailleurs), ou d’utiliser un framework IoC pour gérer ses singletons. Pour des cas simples comme le nôtre, cela nous facilite donc grandement la vie. Pour des cas plus compliqués, où l’on aura par exemple besoin d’AOP, il faudra alors utiliser un framework comme Spring, qui d’ailleurs fonctionne parfaitement avec Scala (voir par exemple https://github.com/ewolff/scala-spring )
  • Elle utilise le nouveau langage CQL proposé dans les dernières versions de Cassandra, ce qui permet d’avoir un code simple et assez proche d’une base de données classique, ce qui facilite grandement son utilisation par rapport à l’API Hector “classique”

En conclusion

Même si le code proposé ici semble très simple, sa mise en place et son développement ont été assez coûteux. Les différents plugins Scala ne sont pas toujours très stables, le langage est très différent de Java : si on compare cette expérience à du code Groovy, par exemple, Scala a une courbe d’apprentissage beaucoup plus élevée et une communauté nettement moins mature.

Cependant, cette expérience est particulièrement positive sur deux points :

  • L’application finale fonctionne très bien
  • Le code est effectivement beaucoup plus concis que du code Java

Scala peut donc permettre de coder des applications Java EE de manière plus rapide, et surtout plus lisible, à partir du moment où l’on passe la barrière de la courbe d’apprentissage, laquelle est tout de même assez rédibitoire en termes de coût.