Retour sur Devoxx 2016 : WildFly Swarm

Cette année Devoxx France s’est tenu pendant 3 jours du 20 au 22 avril au Palais des Congrès de Paris. Infotel a permis à de nombreux collaborateurs de participer à cette éventement.

Frédéric JOSEPH nous fait un retour sur WildFly Swarm


WildFly Swarm – A quoi ça sert ?

WildFly, anciennement JBoss Application Server, est un serveur d’application Java EE 7 de la société Red Hat.


WildFly Swarm est un projet se basant sur WildFly 9 et offrant une approche innovante pour le packaging d’applications Java EE en incluant le code applicatif et les dépendances du serveur au sein d’un unique jar exécutable (fat-jar ou uberjar).

Serveur d’applications monolithique vs « uberjar »

Lors de l’utilisation d’un serveur d’applications monolithique, il faut préalablement installer le serveur puis déployer l’application dessus.

Ce serveur fournit généralement bien plus de fonctionnalités (EJB, JMS, JSF…​) que celles exploitées par l’application Java EE.

Dans un uberjar « WildFly Swarm », seules les composantes de WildFly AS (on parle de « fraction ») nécessaires à l’application sont embarquées dans le jar.
On obtient ainsi un serveur d’applications personnalisé plus léger et démarrant plus rapidement qu’un serveur Java EE « classique ».

De part son fonctionnement, WildFly Swarm incite les développeurs à découper une application Java EE en plusieurs modules distincts et autonomes, afin de ne pas embarquer toute la stack Java EE dans un unique fichier jar (qui serait très volumineux).


Chacun des modules peut alors être un micro-service à part entière pouvant être remplacé, mis à jour ou déployé sur de nouvelles machines de manière indépendante des autres modules.


Du fait qu’une application soit constituée d’un unique jar exécutable, il devient également très facile d’automatiser son déploiement en l’intégrant par exemple au sein d’un conteneur docker (plugin Maven docker-maven-plugin).

Mise en oeuvre

L’utilisation de WildFly Swarm est vraiment très simple avec Maven.

Pré-requis

Les versions minimales pour exploiter WildFly Swarm sont :

  • JDK 8

  • Maven 3.2.5

Modification du POM

  • Package
    <packaging>jar</packaging>

    Il devient inutile de réaliser le package de l’application sous la forme d’un war.

    Toutefois, cela reste possible et l’on obtiendra une archive war valide qui sera encapsulée dans le uberjar à la place du jar.


  • Plugin Maven

    Ajout du plugin Maven

    <plugin>
        <groupId>org.wildfly.swarm</groupId>
        <artifactId>wildfly-swarm-plugin</artifactId>
        <version>${version.wildfly-swarm}</version>
        <configuration>
          <mainClass>com.example.rest.Main</mainClass>
          <properties>
            <swarm.http.port>8080</swarm.http.port> <!-- Already the default value -->
            <swarm.context.path>/</swarm.context.path> <!-- Already the default value -->
          </properties>
          <jvmArguments>
            <jvmArgument>-Xmx128m</jvmArgument>
          </jvmArguments>
        </configuration>
        <executions>
            <execution>
                <phase>package</phase>
                <goals>
                    <goal>create</goal>
                </goals>
            </execution>
        </executions>
    </plugin>
  • Dépendances

    Ajout des fractions du serveur d’applications dont l’application à besoin.

    Exemple pour JAX-RS

    <!-- Java EE 7 dependency -->
    <dependency>
      <groupId>javax</groupId>
      <artifactId>javaee-api</artifactId>
      <version>7.0</version>
      <scope>provided</scope>
    </dependency>
    <!-- Wildfly Swarm Fractions -->
    <dependency>
      <groupId>org.wildfly.swarm</groupId>
      <artifactId>jaxrs</artifactId>
    </dependency>

Code de l’application

@Path("/hello")
public class HelloWorldEndpoint {
 
  @GET
  @Produces("text/plain")
  public Response doGet() {
    return Response.ok("Hello from WildFly Swarm!").build();
  }
}


@ApplicationPath("/rest")
public class RestApplication extends Application {
}


public class Main {
 
    public static void main(String[] args) throws Exception {
 
        Container container = new Container();
 
        JAXRSArchive deployment = ShrinkWrap.create(JAXRSArchive.class, "my-app.war");
        deployment.addClass(RestApplication.class);
        deployment.addClass(HelloWorldEndpoint.class);
        deployment.addAllDependencies();
        container.start().deploy(deployment);
    }
}


La classe Main sert à configurer le conteneur Java EE et à déployer les ressources programmatiquement (facultatif si on package en war).

Génération/Exécution de l’application

La génération de l’archive s’effectue de manière classique.

mvn package

Le dossier target contient alors le jar de l’application ainsi qu’une archive *-swarm.jar

Si on ouvre cette archive jar, on trouve principalement :

  • un répertoire m2repo contenant l’ensemble des librairies nécessaires à l’application

  • un répertoire _bootstrap contenant le jar de l’application

  • un répertoire META-INF contenant les fichiers de configuration nécessaires au uberjar dont notamment :

    • wildfly-swarm.properties : propriétés définies par l’utilisateur (ou par défaut)

      #Generated by WildFly Swarm
      #Sun May 08 14:52:08 CEST 2016
      swarm.bundled.dependencies=true
      swarm.context.path=/
      swarm.http.port=8080
      swarm.app.artifact=hello-swarm-infotel.jar
    • MANIFEST.MF : fichier Manifest standard indiquant la classe Main de bootstrap (Main-Class), ainsi que la classe Main de l’application (Wildfly-Swarm-Main-Class).

      Manifest-Version: 1.0
      Main-Class: org.wildfly.swarm.bootstrap.Main
      WildFly-Swarm-Main-Class: com.example.rest.Main

      Les autres fichiers de configurations servent à lister les dépendances de l’application et des modules WildFly Swarm.

Le lancement de l’application s’effectue à l’aide de la commande java -jar *-warm.jar ou avec la commande maven

mvn wildfly-swarm:run

L’application est alors opérationelle comme une application déployée sur un serveur Java EE « classique ».

Et voici comment réaliser un micro-service, exposant un Web Service REST, sous la forme d’un uberjar contenant un serveur Java EE personnalisé et dont la taille est seulement de 38.6 Mo.


Pour aller plus loin

Les possibilités de WildFly Swarm vont bien au-delà des limites de cet article (security, monitoring, message JMS…​).


Quelques liens utiles :



Les retours d’Infotel sur le Couchbase Live France 2015

Infotel continue d’approfondir son expertise Big Data en permettant à des collaborateurs de participer à des TechDays comme le Couchbase Live France 2015.


Couchbase Live France 2015


Quelques retours enrichissants …



Couchbase 4, les nouveautés


Lors du Couchbase Live France 2015, a été présentée la nouvelle version Couchbase server 4.0. Voici ses principales nouveautés :


N1ql
Couchbase frappe fort en créant une variante du SQL. Couchbase met en avant les forces qui ont fait le langage SQL, à savoir un langage qui permet de « décrire les données » que l’on veut sans avoir à définir le « comment récupérer ses données ». Dans la même optique, Cassandra a déjà sorti sa version de SQL, le CQL. Couchbase va plus loin, n1ql pour Non-first Normal Form Query Language (prononcé « nickel ») permet de « faire du SQL sur du JSON ». C’est à dire, faire du SQL sur des données dont le format n’a pas été prédéfini. Le N1ql permet de faire des projections (récupérer une partie du document) ainsi que des jointures (lier les documents). Couchbase a ainsi profité de ce nouveau langage pour sortir des drivers JDBC et ODBC. On peut ainsi brancher les outils de BI classiques comme Tableau directement sur Couchbase. A noter qu’il est possible de mettre à plat le JSON (UNNEST) de façon similaire à l’UNWIND de MongoDB. Il est ainsi possible de générer un result-set flatté.

Pour en savoir plus :

Global Secondary Indexing(GSI)
Couchbase inclut un nouveau service d’indexation permettant des recherches efficaces sur les champs secondaires (autre que la key). Ce service est délocalisé des données de façon à éviter les scatter/gather des views. Il ne remplace pas les views qui sont toujours présentes. A noter que les indexes GSI sont mis à jour en asynchrone pour ne pas perturber la stabilité des performances du service key/value. On note ici que Couchbase ajoute des fonctionnalités en veillant bien à ne pas perdre en performance.


ForestDB
Le WiredTiger de Couchbase ? Ce nouveau moteur a été implémenté par Couchbase et a été intégré dans le GSI. Il ne remplace pas le moteur de stockage principale key/value de Couchbase. On peut espérer de bonne performance pour ce moteur pour l’instant dédié aux index.


Multi dimension scaling
Derrière cette expression, Couchbase veut montrer que sa base est un modèle en termes de scalabilité. Avoir une scalabilité horizontale pour le moteur key/value est incontestée, cependant elle l’est moins concernant la recherche sur index. Couchbase reconnaît la faiblesse des views : il faut à chaque fois faire un scatter/gather qui implique tous les nœuds du cluster. Couchbase 4.0 permet d’activer un ou plusieurs des services data/index/query sur chacun des nœuds. On peut donc désormais s’offrir un énorme serveur pour l’indexation afin d’accélérer grandement les requêtes sans faire de compromis sur le service key/value.


Couchbase 4 VS MongoDB : Faut-il choisir entre les performances et les fonctionnalités ?


Les nouveautés proposées dans Couchbase Server 4.0 nous ont fortement incités à faire la comparaison avec MongoDB.
MongoDB a connu un franc succès grâce à sa facilité d’utilisation et sa richesse de fonctionnalités au sein de l’univers NoSQL. De son coté, en plus des performances et de la facilité d’administration, Couchbase peut désormais afficher des fonctionnalités plus étendues.


Performance : MongoDB a misé sur WiredTiger
MongoDB , en intégrant le moteur WiredTiger, essai de faire oublier les critiques de son moteur MMAP v1.
MongoDB 3.2 établi WiredTiger comme stockage par défaut, soit seulement 1 version après son intégration.

Couchbase, de son côté, a mis un point d’honneur à ne pas proposer une fonction recherche qui aurait pu mettre en péril les performances du moteur key/value. Couchbase livre donc le N1ql avec le multi dimension scaling.


Fonctionnalités : Couchbase Server 4.0 est une petite révolution
Force est de reconnaitre que MongoDB avait jusqu’alors une certaine avance en terme de fonctionnalités/agilité.
Avoir le maximum d’agilité sur une base NoSQL a depuis longtemps été la force de MongoDB :
Ce schéma qui met en évidence le rapport performance/Fonctionnalités nous a grandement rappelé celui présenté par MongoDB depuis plusieurs années:

A travers ce schéma, il faut comprendre que MongoDB souhaite avoir le maximum de fonctionnalités sans sacrifier la scalabilité.

Ravi Mayuram(SVP Products & Engineering) lors du Couchbase Live France 2015 dit :
« Couchbase 3 avait la scalability, couchbase 4 ajoute la flexibilité »


MongoDB ne semble pas souhaiter se faire dépasser sur ce terrain et dans la version 3.2, il ajoute la possibilité de faire des left outer join via le Framework d’agrégation.

Avec cette avancée significative, Couchbase a proposé le 18 novembre un Webinar sur la migration MongoDB vers Couchbase.http://www.couchbase.com/nosql-resources/webinar


De plus, Couchbase propose désormais des formations en ligne (dont certaines gratuites) afin de rendre sa base encore plus accessible à tous. http://training.couchbase.com/online


Faire un choix aujourd’hui
La concurrence est désormais clairement établie et nous autres utilisateurs ne pouvons que nous en réjouir.
Chacune de ses bases de données fait des efforts considérables pour combler ses faiblesses, mais nous conseillons encore de choisir :

  1. MongoDB lorsque l’agilité est un critère déterminant,
  2. Couchbase lorsque les performances key/value sont déterminantes.


Caching use cases


Au fil des présentations de la journée, l’un des points qui ressort est l’intérêt du « Managed cache » intégré à Couchbase Server. La présence d’un cache entre la couche applicative et la base de données permet de meilleures performances car la donnée est disponible en RAM et n’a pas besoin d’être lue depuis le disque. Il en va de même en écriture, la mise à jour dans la base pouvant se faire de manière asynchrone à partir du cache.

Une solution pour cela, notamment avec des bases de données SQL, est d’utiliser un cache distribué indépendant de la base, comme Memcached. Cette solution présente cependant plusieurs inconvénients :

  1. L’infrastructure est plus complexe,
  2. La gestion du cache et des transferts de données entre la base et le cache nécessite un effort supplémentaire,
  3. L’extension des capacités est plus délicate.


Le cache intégré à Couchbase Server est au cœur du système de gestion de base de données depuis sa création. Il permet de ne pas avoir de composant supplémentaire dans l’architecture de l’accès aux données. Il est géré en monitorant la lecture et l’écriture des documents par les clients. Les données les plus utilisés sont conservés en mémoire, les moins utilisés en sont éjectés pour laisser la place à d’autres. La persistance sur disque et la réplication sont effectuées de manière asynchrone, via des queues.

Couchbase nous a présenté au cours de cette journée plusieurs cas de migration d’une telle architecture vers un cluster Couchbase. Ont notamment été cités : PayPal, Tesco, Walmart, Experian et Sky. Le cas d’Amadeus, présenté comme le plus gros remplacement de Memcached à l’échelle mondiale, a été plus détaillé lors d’une présentation par Ludovic DUFRENOY, Software Development Manager. Amadeus est passé de 27 nœuds MySQL et 24 nœuds Memcached à une trentaine de nœuds Couchbase, et ils sont visiblement très satisfaits des performances de leur nouvelle infrastructure, avec un temps de réponse du cache inférieur à 0.5ms.

On retiendra donc que les retours clients mettent l’accent d’une part sur les performances, conservées malgré l’ajout de fonctionnalités, et d’autre part sur la simplification de l’infrastructure, avec la simplification d’augmentation des capacités et la réduction des coûts qui en découlent.

Communiqué de presse d’Amadeus en Français (14/11/2013)
http://www.amadeus.com/web/amadeus/fr_FR-FR/Page-daccueil-Amadeus-Home/Actualit%C3%A9s-et-%C3%A9v%C3%A9nements/Communiqu%C3%A9s-de-presse/2013-11-14-Amadeus-et-couchbase/1259071475442-Page-AMAD_DetailPpal?assetid=1319575273950&assettype=PressRelease_C


Couchbase mobile use cases


Couchbase Mobile se compose de trois éléments :

  1. Sync Gateway
  2. Couchbase Lite
  3. Couchbase Server

« Sync Gateway » est un serveur de synchronisation qui permet d’activer Couchbase Server et de gérer en temps réel les flux de collaboration sur tous types de supports, via la messagerie instantanée, le cloud ou encore les réseaux sociaux. Il a pour but de copier les données internes au système entre les serveurs Couchbase et Couchbase Lite. Il gère aussi :

  1. l’authentification
  2. le contrôle des données
  3. la validation des mises à jour
  4. la duplication des données avec Couchbase Server

« Couchbase lite » est une base de donnée NOSQL très légère, intégrée directement dans le périphérique. Les informations sont directement écrites en local, ce qui permet d’avoir une latence très faible lors des écritures et lectures en base. Couchbase Lite représente les données dans le format JSON, ce qui permet une grande souplesse et ne nécessite plus de définir une structure de donnée précise. Couchbase Lite se synchronise avec Couchbase Server dès que c’est possible et s’occupe de la résolution des conflits potentiels.

Ryanair, qui a présenté ce use case, faisait face à plusieurs problèmes avec son application mobile de réservation de vol. Les plus importants étaient la lenteur de l’application et la nécessité d’avoir une bonne connexion internet pour pouvoir réserver un vol en un temps acceptable et de n’ importe où (aéroport, en vol, pays étranger).

Couchbase Mobile permet donc à Ryanair d’améliorer grandement la latence, pour réserver un vol il ne faut que 2 minutes contre 5 minutes auparavant et un accès hors-ligne aux données sur les vols. Les clients peuvent donc réserver un vol même sans avoir une connexion internet. Cela est très important pour eux car leurs voyageurs n’ont pas accès aux données mobiles en dehors de leur pays ou dans l’avion et la plus part du temps les connexions wifi gratuites sont très lentes.

La mise en place de Couchbase Lite et de Sync Gateway étant simple, ils ont pu mettre en place la nouvelle application en une semaine avec l’aide des techniciens de Couchbase et grâce à la communauté de développeurs très active.

Voir la présentation complète Ryanair Couchbase Live : http://docslide.us/travel/how-ryanair-reduced-booking-time-from-5-to-less-than-2-minutes-couchbase-connect-2015.html



seedstack.org : la solution open source de PSA

seedstack_image



Un besoin permanent de productivité et de cadrage

Bien avant l’apparition du langage Java, PSA construisait déjà des frameworks permettant d’accélérer le développement logiciel et de répondre au mieux à ses besoins métiers. Lorsque Java est arrivé avec son lot de frameworks et d’outils, les frameworks PSA ont évolués pour devenir des couches d’intégration autour de frameworks existants et ainsi fournir des outils communs à l’ensemble de ses développeurs. Cependant, ce travail d’intégration d’outils qui n’ont pas été prévus pour fonctionner ensemble et difficiles à configurer a fini par montrer ses limites. De nombreux projets restaient bloqués sur des frameworks obsolètes parce que « montée de version » voulait dire réécriture complète du projet. Le manque de modularité se faisait cruellement sentir. De plus, même si les outils étaient communs (Spring, Struts, etc.), ils leur manquaient de l’opinion et des bonnes pratiques. C’est à dire qu’à chaque fois qu’un développeur changeait de projet il avait tout à réapprendre: organisation, conventions, etc…


Un programme d’entreprise

Début 2013, PSA a donc décidé de rassembler une équipe pour faire face à ce problème. Composée de deux architectes et de deux à huit développeurs selon le plan de charge (moitié PSA, moitié collaborateurs Infotel en mission pour PSA), l’équipe s’est donc attelé à la tâche : réécrire une solution complète nommée SeedStack. Dès l’origine du projet, des orientations structurantes ont été faites.


Des choix novateurs

Premièrement, la stack n’intègrerait pas Spring, comme les précedants frameworks. Elle aurait un noyau plus léger et plus modulaire pour éliminer le couplage. Le micro framework Nuun.io a été choisi pour d’adresser ces éléments grace à son architecture kernel/plugin. Il confère une grande agilité à SeedStack qui a pu grandir et se réorganiser depuis deux ans sans rencontrer aucun obstacle. Chaque plugin expose ses API (Application Programming Interface) qui servent de contrats avec les développeurs et facilitent ainsi les montées de version. Certains exposent également des SPI (Service Provider Interface) permettant aux développeurs d’étendre les fonctionnalités du framework et donc de répondre à tous leurs besoins.



Mettre le métier au cœur du développement et le cadrer

Deuxièmement, il a été décidé de promouvoir des styles d’architectures de type REST (Representational State Transfer) et DDD (Domain Driven Design). Le REST via ses API hypermedia permet aux applications d’exposer des ressources Web simples à utiliser, qui garantissent une compatibilité à long terme tout en permettant une grande évolutivité. Son support a été développé en se basant sur les spécifications JAX-RS (via Jersey) et HAL. Le DDD quant à lui permet de se recentrer sur le domaine métier. Il remet la conception au coeur du travail de développeur, alors qu’elle est trop souvent délaissée au profit d’architecture de type CRUD : correspondance 1-1 entre de la base de données et l’IHM. Aucune solution satisfaisante n’étant disponible pour son implémentation, il a été décidé de développer un nouveau framework adressant la partie tactique du DDD.

Enfin, pour la partie Web, un framework a été développé pour combiner le meilleur d’AngularJs, RequireJs, et Bootstrap. L’utilisation du REST côté serveur et d’une SPA (Single Page Application) côté UI permet ainsi, le découplage du front et du back qui peuvent maintenant avoir des cycles de vie séparés. Par ailleurs, ce framework Web n’est pas en reste côté modularité car il permet via un système de fragments de composer son application à partir de modules indépendants.



Une suite Open Source

Suite à ces choix SeedStack a connu un départ rapide et les gains en productivité ne se sont pas laissés attendre. La première version a été finalisée après seulement 6 mois de développement. Dès lors, elle a été intégrée par des projets pilotes, qui ont permis à la solution de se développer et de s’affiner. Avec un rythme de 3 versions par an, SeedStack a connu des évolutions fréquentes. Début 2015, une quarantaine de projets (dont la moitié en production) utilisaient déjà cette stack. Conscient de l’intérêt de sa solution, PSA a alors décidé de publier SeedStack sous une license libre : la MPL 2.0 (Mozilla Public License 2.0). Après un audit juridique et technique ainsi qu’un peu de refactoring, la stack a été publié sur GitHub en version béta en mai 2015. Puis, après quelques mois de travail une première version open source a été publiée en Juillet. Loin d’achever cette « success story », la mise en open source lance de nouveaux défis : tout d’abord continuer d’améliorer la stack, mais aussi communiquer et trouver de nouveaux partenaires.

Des premières contributions extérieures ont été enregistrées et je vous encourage tous à venir participer. Il n’y a pas de petites contributions ! Que ce soit de la documentation, des rapports de bug ou du code, toutes les contributions sont les bienvenues.



Infotel, fier d’être partenaire technologique de Datastax

Pourquoi ce partenariat ?

1. Infotel a récemment lancé son plan stratégique appelé « Plan Performance 2016 » dans lequel le Groupe a pour objectif d’accompagner ses clients dans leur stratégie Big Data. Ce partenariat permet à Infotel de compléter son expertise dans la gestion des grandes bases de données et élargir sa maîtrise de l’écosystème Big Data dans lequel Datastax joue un rôle majeur.


2. Pour Datastax, ce partenariat met à disposition de ses clients l’expérience d’intégrateur d’Infotel déjà impliqué dans de nombreux développements autour des systèmes distribués et des grandes bases de données. Infotel participe à la migration des grands comptes vers le NoSQL, en France comme à l’international.


Quelle est la valeur ajoutée pour les clients d’Infotel ?

Infotel fournit à ses clients un support adapté à leurs besoins pour intégrer les nouveaux outils du NoSQL, comme Cassandra, dans leur SI. Les capacités de Cassandra pour l’écriture rapide de quantités massives d’informations en font en effet une des bases de données majeures de la tendance NoSQL. Distribuée par Datastax, elle représente un outil de choix lorsque l’on cherche une base de données scalable sans single point of failure. Appartenant à la famille des bases de données colonnes, elle constitue une véritable alternative face à d’autres systèmes de stockage structurés.

Interface OpsCenter permettant la supervision de clusters Cassandra


Infotel complète son panel de technologies mises en œuvre sur ses plateaux et vous accompagne grâce à ce partenariat. Avec Infotel, vous pouvez fournir à vos équipes projet le support Datastax dont elles ont besoin pendant les cycles de développement et jusqu’à la mise en production de vos applications.


Vous souhaitez en savoir plus ?

N’hésitez pas à nous contacter : ingenierie.technique@infotel.com



Retour sur DevoxxFR 2015 CDI

Cette année encore, de nombreux Infoteliens ont participé au Devoxx France qui s’est tenu pendant 3 jours du 8 au 10 juin au Palais des Congrès de Paris.

François NASSOY nous fait un retour sur CDI

Introduction

Contexts and Dependancy Injection (CDI) est une spécification (JSR 299) de JAVA EE qui défini une interface de programmation pour la gestion des injections des dépendances.
Le mot d’ordre de CDI pourrait être : Avec CDI, on injecte tout dans tout!
Les principaux services offerts par CDI sont :

  • Contexte : la capacité à lier le cycle de vie et les intérractions des composants stateful ou l’ensemble des contextes est extensible.
  • L’injection de dépendance: La capacité d’injecter des componants de manière typée et de choisir le spectre d’utilisation (developpement / deploiement)

CDI offre aussi, un certain nombre de services complémentaires :

  • L’intégration de l’Expression Language (EL) permettant à tous les objets contextuels d’être utilisés directement dans les pages JSF et/ou JSP.
  • La capacité de décorer les objects injectés
  • La capacité d’associer des interceptors avec des components en utilisant typesafe interceptor bindings
  • Un modèle de notification d’evénement
  • L’ajout d’un nouveau Scope au trois classiques (request, session and application) : scope conversation
  • Une SPI permettant une intégration propre de CDI aux conteneurs tiers

Premier pas avec CDI

Injection de dépendance

L’injection avec CDI est tres simple. En effet, pour injecter un bean, il suffit d’annoter une classe, un attribut de classe, ou une méthode (setter, constructeur) avec l’annotation @Inject.

Injection d’un DAO :

  • Sur l’attribut

    @inject
    private MyClassDao myClassDao
  • Sur le setter

    private MyClassDao myClassyDao
    @inject
    public void setMyClassDao(MyClassDao myClassDao){
    return myClassDao;
    }
  • Sur le constructeur

    private MyClassDao myClassyDao;
    @inject
    public MyClass(MyClassDao myClassDao){
    this.myClassDao = myClassDao;
    }

Qualifier

Il est tres frequent qu’un bean posséde plusieurs implémentations. L’injection d’un tel bean via @inject provoque une erreur d’ambiguité. En effet, qu’elle implémentation utiliser ?
Pour pallier se problème, CDI propose les Qualifier. L’idée est que chaque implémentation soit qualifié, ie. nommé, et qu’à l’injection du bean soit spécifié quelle implémentation doit être utilisée.
Pour mettre en place cela, il faut :

  • Créer autant d’annotation que de Qualifieur annonter @Qualifier
  • Annonter les implémentations avec le Qualifier @NomQualifier
  • Ajouter lors de l’injection le Qualifier : @inject @NomQualifier
  • Création des annotations
    @Qualifier
    @Retention(RUNTIME)
    @Target({FIELD, TYPE, METHOD, PARAMETER})
    public @interface MyFirstImplDao {
    }
     
    @Qualifier
    @Retention(RUNTIME)
    @Target({FIELD, TYPE, METHOD, PARAMETER})
    public @interface MySecondImplDao {
    }
  • Annotation des implémentations

    @myFirstImplDao
    public class MyFirstImplDaoImpl implements MyClassDao {...}
     
    @mySecondImplDao
    public class MySecondImplDaoImpl implements MyClassDao {...}
  • Injection

    @inject @mySecondImplDao
    private myClassDao;

CDI defini un Qualifier par defaut via l’annotation @Default, permettant ainsi de ne pas devoir préciser le qualifier lors de l’injection.

  • L’injection
    @inject
    private myClassDao;
  • Equivaut à l’injection

    @inject @Default
    private myClassDao;

Produces

Toutes applications JAVA, ou presque, utilisent des librairies externes (log4j, Hibernate, etc.). CDI permet nativement d’inject des beans de librairie externe du moment qu’elles soient elles même des librairies CDI.

La différence entre une librairie CDI et une librairie non CDI est la présence ou non d’un fichier, beans.xml, dans l’archive. La librairie CDI devant posséder ce fichier.

CDI propose un mecanisme pour résoudre le problème d’injection de bean d’une librairie non CDI. Ce mécanisme consiste à rendre injectable un bean d’une librairie tiers en utilisant les Producer CDI, annotation @Produces. Ces produers ont pour but de de créer des objects injectables qui peuvent être de types primitifs, des beans ou encore des ressources telles qu’un entityManager, une connection JMS, etc.

Pour rendre un élement (méthode, attribut, beans, ..) injectable, il suffit de le nommer via un Qualifier et de l’annonter via @Produces.

  • Injection d’un type primitif qui ne varie pas au Runtime
    public ClassA {
    private int myNumber = 10;
     
    @Produces @MyNumber
    int getMyNumber() {
    Return myNumber;
    }
    }
    Public ClassB {
    @Inject @MyNumber
    Int myNumber;
    }

    le ClassB.myNumber est directement initialisée via ClassA.getMyNumber() à 10

  • Injection d’un type primitif qui varie au Runtime
    public ClassA {
    private java.util.Random random = new java.util.Random( System.currentTimeMillis() );
     
    java.util.Random getRandom() {
            return random;
    }
     
    @Produces @Random
    int next() {
        return getRandom().nextInt(maxNumber);
    }
    }
    public ClassB {
    @Inject @Random
    Instance<Integer> randomInt;
     
    Int myRandom;
     
    void ClassB() {
    myRandom = randomInt.get()
    }
    }

l’injection se fait sur une déclaration d’une instance contextuelle de l’objet, utilisable ensuite via la méthode get().

  • Sans CDI
    public class MyDAO {
    @PersistanceContext(unitName="cdiEM")
    private EntityManager em;
    }
  • Avec CDI
    public class DatabaseProducer() {
    @Produces
    @PersistanceContext(unitName="cdiEM")
    @MyDatabase
    private EntityManager em;
    }
    public class MyDAO {
    @inject
    @MyDatabase
    private EntityManager em;
    }

Injection d’élement d’une librairie externe comme par exemple un Logger :

  • Sans CDI
    public class MyClass {
    private static final Logger LOG = Logger.getLogger(MyClass.class);
    }
  • Avec CDI
    public class LoggerProducer() {
    @Produces
    public Logger produceLogger(InjectionPoint injectionPoint) {
    return Logger.getLogger(injectionPoint.getMember().getDeclaringClass().getName());
    }
    public class MyClass {
    @Inject
    private static final Logger LOG;
    }

    La méthode du producer à comme paramétre un injectionPoint, permettant entre autre, de récupérer les informatiosn sur le nom de la classe où l’élement est injecté.

Nommage EL

CDI permet de donner un nom EL (Expression Language) aux beans, via l’annotation @Named, afin qu’ils soient accessibles dans les pages JSF.

  • @Named
    public class MyBean {...}
  • Équivaut �
    @Named(myBean)
    public class MyBean {...}
  • Et s’utilise ainsi dans les pages JSF
    <h:outputLabel value="#{myBean.oneMethod}" />

Alternative

CDI propose une autre fonctionnalité tres interressante, la possibilité de définir une implémentation alternative à un bean.

Un bean peut avoir plusieurs implémentations utilisées à des fins différentes et positionnées lors des developpements par injection via leurs qualifiers. CDI propose de définir des implémentations qui pourront être choisies directement au moment du deploiement permettant ainsi de changer une implémentation sans modification de code.

  • Gérer une logique métier spécifique au client determinée au runtime
  • Spécifier des beans qui sont valides suivant des scénarios de deploiement spécifiques
  • Créer des versions MOCK des beans

Pour créer une alternative, il faut :

  • créer une implémentation
  • annoter la classe avec @alternative
  • definir les qualifiers impactés par l’alternative
  • déclarer l’alternative dans le beans.xml
  • Dao bean avec trois implémentations
    @myFirstImplDao
    public class MyFirstImplDaoImpl implements MyClassDao {...}
    @mySecondImplDao
    public class MySecondImplDaoImpl implements MyClassDao {...}
    @mytThirdImplDao
    public class MythirdImplDaoImpl implements MyClassDao {...}
  • Création de l’alternative
    @alternative
    public mockDAO impléments MyClassDao {}
    Ajout des qualifier devant être remplacer par l’alternative (1 ou plusieurs)
    @alternative
    @myFirstImplDao
    @mySecondImplDao
    public MockMyClassDAO impléments MyClassDao {}
  • L’injection des implémentations ne change pas
     
    @inject @mySecondImplDao
    private myClassDao;

    à ce stade, c’est toujours l’implémentation MySecondImplDao qui sera utilisée

  • Activation de l’alternative dans le beans.xml
    <alternatives>
       <class>fr.exemple.alternative.MockMyClassDAO</class>
    </alternatives>

    à partir de cette instant, c’est l’implémentation alternative, ici le mock, qui sera utilisé en lieu et place des implémentations MyFirstImplDao et MySecondImplDao.
    L’alternative ne portant pas le qualifier de l’implémentation MyThirdImplDao, les injections liés à cette implémentation ne seront pas impactées par l’alternative. Ce sera toujours l’implémentation MyThirImplDao qui sera utilisée.

Event

CDI offre aussi la possibilité aux beans de produire et de consommer des evénements (events). Ce mécansime permet une interaction entre beans via un couplage asynchrone sans utiliser JSM. Il permet aussi de synchroniser et capter les changements d’état de bean stateful.

Un évement est matérialisé soit par un event objet soit par un playload et est qualifié via un ou plusiuers event qualifiers. Ces qualifiers permettent de determiner les events à produire ou à observer pour un bean donné.

    Le principe est simple :

  • mise en place d’un event à observer
    • création d’un qualifier pour l’event
    • création de l’event
    • création de la(des) méthode(s) déclanchant l’event
  • mise en place des observer
    • création de la(des) méthode(s) écoutant l’event
  • Qualification de l’event
    @Qualifier
    @Target({FIELD, PARAMETER})
    @Retention(RUNTIME)
    public @interface Updated {}
  • Création de l’event
    @Inject @Updated
    Event<User> userEvent;
  • Création de la méthode déclanchant l’event
    public void myMethod(Event<User> userEvent) {
       ...
       userEvent.fire(user);}
  • Création d’un observateur quelque soit le qualifier de l’event
    public void onAnyUserEvent(@Observes User user) {}

    méthode déclanchée pour tout event de type userEvent

  • Création d’un observateur pour un events spécifique
    public void afterUserUpdate(@Observes @Updated User user) {...}

    méthode déclanchée pour les event qualifiés @Updated

Conclusion

Bien que cet article ne presente qu’un bref appercu des possibilités de l’API CDI, il transparait assez clairement que CDI apporte un vrai plus à JAVA EE6, de part sa facilité d’utilisation et ses nombreuses fonctionnalités. CDI est une remise en cause de la façon de traiter l’injection de dépendances et les AOP. Il simplifie, il réduit, il se débarrasse de l’héritage, des idées dépassées.

Dans le domain des injections de dépences, des AOP, etc., une API revient reguliérement, Spring. Bien que à mon sens Spring ait encore une longueur d’avance sur CDI, CDI ne démerite pas, loin de là même. Il offre une tres bonne altérnative voir un complément. En effet, des mécanismes permettent d’intégrer les deux API.