Tag :EJB3

Architecture stateful vs stateless

Le 22 novembre, le Lyon JUG propose une soirée autour des architectures Stateful et Stateless. Deux équipes vont donc s’affronter sur le ring du Lyon JUG. Du côté Stateful, Antoine Sabot-Durand nous fera une présentation intitulée “Stateful is Beautiful”, revenant aux sources de Java EE (CDI, EJB 3…), le tout articulé autour d’une démo! Et du côté Stateless, on retrouvera Philippe Charrière et Loïc Descotte, tous les deux co-auteurs de l’ebook Play.Rules qui nous parleront donc des concepts des architectures Stateless à travers une démo basée sur Play Framework!. Pour vous mettre l’eau à la bouche, voici un interview des speakers : les mêmes questions ont été posées à chaque équipe (à part la dernière), et elles n’ont évidemment pas eu accès aux réponses de l’équipe adverse avant la diffusion de cet interview.

@antoine_sdAntoine Sabot-Durand est consultant et architecte Java EE chez Ippon Technologies. Il intervient sur toute sorte de missions : conceptions d’architecture applicative, audits d’applications existantes, formations. Il est également en charge de la capitalisation des savoir faire au sein de la société. Il a acquis une expertise sur Java EE et plus particulièrement sur EJB 3.X et CDI. Il est l’auteur de quelques articles ayant alimenté le débat sur les standards et les choix technologiques sur les développements Java comme “Les rendez-vous manqués de Spring” ou plus récemment une suite d’article sur Java EE 6. Il est également membre de l’Expert Group CDI 1.1 et technical Leader sur le module Seam Social du projet Open Source Seam 3. Vous pouvez suivre Antoine sur Twitter ou Google+.

@antoine_sdPhilippe Charrière s’est présenté lui-même comme suit : “Je suis “avant-vendeur” à Lyon chez Steria. Avant d’être “ingénieur informaticien” j’ai commencé à coder sur une TI57 (beaucoup ne doivent pas savoir ce que c’est, normal j’ai 42 ans (ça c’est geek)) et depuis la passion du code ne m’a plus quitté. J’ai fait différents métiers en passant par technico-commercial, développeur cobol, responsable informatique, chef de projet, architecte .Net (désolé), directeur de projet, responsable technique, avant-vendeur… et ce n’est certainement pas fini. Mais je n’ai jamais lâché “le code”, plutôt multi-techno, ça m’aide à faire des propositions commerciales qui tiennent la route et à la livrer avec des prototypes quand je peux. @Home, c’est Javascript, Coffeescript, Play!Framework, et tout ce qui touche au mobile (grosse passion pour les jouets Apple, mais bidouille aussi Android)”. Vous pouvez consulter le blog de Philippe ou le suivre sur Twitter ou Google+.

Loïc DescotteLoïc Descotte s’est également présenté lui-même : “JUG Leader à Grenoble (Alpes JUG) et développeur chez Kelkoo. Ce que j’aime particulièrement dans le métier/hobby de développeur c’est l’évolution permanente des technologies qui permet de découvrir sans cesse de nouvelles choses. Dès que j’ai un peu de temps j’essaie de parler un peu des frameworks que je teste sur mon blog CoffeeBean. J’ai découvert Play début 2010 grâce à une présentation de Guillaume Bort. J’ai tout de suite été séduit par la puissance, la simplicité de ce framework, qui contrairement a pas mal de ses concurrents côté Java (Wicket, JSF…) ne cherche pas à masquer les principes et le fonctionnement du Web.” Vous pouvez également le suivre sur Twitter ou Google+.

Cet interview a été préparé conjointement par Agnès CREPET et Cédric EXBRAYAT, deux membres de la team du Lyon JUG. Merci également à Cyril Lacôte de l’équipe du podcast Cast-IT pour son aide sur la relecture de cet interview.

Agnès & Cédric : Pour introduire un peu les concepts d’une architecture avec ou sans état, comment définiriez-vous ce qu’est un état ?

Loïc (Equipe Stateless): Dans une application il existe (presque) toujours un état. Lorsqu’on parle d’architecture sans état il s’agit souvent d’un raccourci pour dire qu’il n’y a pas d’état au niveau middleware (sur le serveur d’application par exemple). Dans ce contexte, l’état est un ensemble de données relatives à une session utilisateur à un instant t. Ces données peuvent comprendre les informations relatives à l’authentification et aux droits de l’utilisateur, un historique des actions effectuées durant cette session (sélection de paramètres d’affichage, sélection de produits sur un site marchand…)

Philippe (Equipe Stateless): Globalement, je dis “comme Loic”. plus spécifiquement, j’aurais tendance à “déshumaniser” le concept et à rattacher l’état à une page plutôt qu’à l’utilisateur, voire même de manière plus abstraite à une ressource (ex: client lourd à la place de la page). Et cet état existe côté client et côté serveur, pas forcément en même temps selon si l’on est en stateful ou en stateless :

  • en stateful : la page/client a un état, dont la représentation/(persistance ?) côté serveur est une session en mémoire quasiment au même moment
  • en stateless : la page/client a un état, dont la représentaion côté serveur est finalement très furtive puisqu’elle peut n’exister qu’au moment où l’on interroge le serveur.

Antoine (Equipe Stateful): Un état est une information temporaire gérée au sein d’une application pour un utilisateur donné ou l’application dans sa globalité. Cette information permet de conserver de manière transitoire des données concernant l’utilisation actuelle de l’application ou un statut d’avancement dans un processus donné de celle-ci.

Agnès & Cédric : Imaginez que vous atterrissiez sur une île déserte et que vous n’ayez la possibilité d’emmener avec vous qu’un seul framework Java de référence pour coder une application, lequel choisiriez-vous ?

Loïc (Equipe Stateless): Si on part du principe qu’il n’y a pas d’électricité sur une ile déserte, il va falloir faire le maximum de chose avec le temps de batterie qu’il nous restera sur notre laptop… Il nous faut donc un framework productif… ensuite je pense que vous vous doutez de la réponse ;)

Philippe (Equipe Stateless): perso, je préférerais partir avec un manuel de construction navale et une canne à pêche. Sinon je partirais avec SL4A sur android + moteur beanshell parce que j’aurais plus de batterie sur mon smartphone que Loic sur son netbook. (Bon, ok, je prendrais Play! aussi parce que je peux utiliser TextMate et que ça consomme moins de ressource)

Antoine (Equipe Stateful): Pour coder : Java EE 6, parce que c’est la solution permettant le plus de choix d’architecture : Stateful ou Stateless, webapp ou client lourd. Sinon la bibliographie Spring est plus volumineuse et avantageuse si on souhaite faire des feux de camp!

Agnès & Cédric : Selon votre approche préférée (stateful/stateless), comment “suivre” et contrôler l’activité d’un client sur mon site? En prenant le fameux exemple d’un client faisant une commande sur un site marchand: comment puis-je lier entre elles les requêtes HTTP d’un même client? Comment je persiste son panier?

Loïc (Equipe Stateless): Si on prend l’exemple de Play, pour lier les requêtes HTTP d’un même client on dispose d’un objet d’accès à la session d’un utilisateur dans les contrôleurs. Cet objet est initialisé à l’aide un cookie sur le navigateur. Ce cookie est signé et crypté pour des raisons de sécurité. Si on veut stocker le contenu d’un panier dans la session utilisateur, on a plusieurs possibilités. La solution la plus pratique et qui sera bientôt la solution la plus standard est d’utiliser les API de stockage côté navigateur fournies par HTML5.

Philippe (Equipe Stateless): Facile! Comme Loïc. Bon je détaille un peu. Pour lier et persister : localstorage (donc il faut faire du js) est une super solution, facile à mettre en oeuvre. Beaucoup l’associe à HTML5, mais en fait la notion de localstorage existait avant, et il existe différents types de localstorage : SQLite, local storage (key-value), DOM Storage, user-data (anciennes versions de navigateurs). Pour plus d’infos : voir cet article “5 Obscure Facts About HTML5 LocalStorage“. Pour les navigateurs plus vétustes, il y a aussi la possibilité d’utiliser les fonctionnalités de storage de flash, il est très facile de discuter en js avec actionscript (et inversement). Pour les inquiets du JS, il existe de très bonnes librairies qui encapsulent et abstraient tout ça, une des plus connues est lawnchair.js de Brian Leroux (de chez NitobiAdobe / Phonegap) et qui fournit tous les adapters nécessaires en fonction des navigateurs. Un des plug-ins lawnchair fait du clé-valeur avec la base SQLite embarquée qui est plus rapide que la version clé-valeur de base (ça s’utilise par contre de manière asynchrone avec des callbacks). C’est aussi intéressant de se coder la sienne au moins pour comprendre les concepts.

Antoine (Equipe Stateful): [Pour lier les requêtes HTTP :] en les stockant dans un contexte session ou mieux conversation. Pas de persistance explicite. Le panier reste en mémoire, il sera sérialisé en cas de besoin (charge importante). Si j’attends une durée de vie plus importante, je peux mettre un listener à la fin de la session pour le stocker explicitement.

Agnès & Cédric : Comment je contrôle la conversation web de mon client : comment gérer par exemple le bouton back du navigateur?

Loïc (Equipe Stateless): Le problème du bouton back du navigateur se pose beaucoup moins avec un serveur stateless. Le principe d’architecture stateless est fortement lié à celui d’architecture RESTful : avec des URL bien définies, n’importe quelle étape de la navigation doit être bookmarkable. Si on revient sur une de ces étapes, le fait d’avoir un serveur stateless fera qu’on ne risque aucune incohérence d’état sur le serveur : la page s’affichera toujours correctement quel que soit le contexte. Si vous avez déjà utilisé des frameworks comme JSF vous savez que ce n’est pas toujours le cas quand vous devez tenir compte de l’état du serveur.

Philippe (Equipe Stateless): Pour le bouton back, cela peut se gérer côté client : toujours avec le localstorage, une solution peut être aussi de faire une application ‘monopage’ (webapp) et de jouer aussi avec les api de gestion de l’historique du navigateur , des hashtags (window.onhashchange), …

Antoine (Equipe Stateful): Plusieurs stratégies en fonction du contexte :

  • Stocker l’état des vues précédentes pour gérer le back
  • Demander à JSF de générer des URL Rest avec prettyface
  • interdire au navigateur de cacher une page pour forcer son rafraîchissement
  • gérer correctement les erreurs d’incohérence entre l’état serveur et l’état client
  • Faire mon rendu en ajax : le bouton back me fera sortir de l’application

Agnès & Cédric : Est-ce possible de gérer plusieurs espaces de travail pour le client, à savoir plusieurs conversations avec la même application dans différents onglets de son navigateur?

Loïc (Equipe Stateless) : Je ne suis pas du tout expert sur cette question, le cookie de session étant partagé entre les différents onglet (du moins sous Firefox et Chrome), en principe on ne peut pas avoir plusieurs sessions en même temps avec ce procédé. Après avec Play tout est possible, on peut très bien se contenter de créer une session côté client, encore une fois avec local storage, et associer une session à une instance de page à l’aide de JavaScript.

Philippe (Equipe Stateless): avec le module Secure de base de Play, ça va pas le faire (perso j’utilise différents navigateurs, ou mode incognito) pour les raisons expliquées par Loic. Quelles solutions ? -> faire sa propre solution d’authentification et passer des infos dans la requête (bof) -> faire avec -> quand tu es connecté sous google tu ne peux l’être qu’avec un seul user -> on perd en souplesse, on gagne en sécurité.

Loic (Equipe Stateless): En dernier recours il existe aussi des plugins pour les navigateurs qui permettent d’avoir des sessions distinctes dans différents onglets via une manipulation des cookies (voir exemple).

Philippe (Equipe Stateless): pour l’aspect “plusieurs espaces de travail” : le localstorage peut prendre plusieurs formes :

  • accessible par l’ensemble des onglets du navigateur (ou par plusieurs instances du navigateurs), bon ok dans le cas de 2 navigateurs de marques différentes, faudra faire plus classique (on parle de localstorage)
  • accessible uniquement sur la page en cours et uniquement pendant la session (on parle de sessionstorage)

Antoine (Equipe Stateful): Yep, CDI contient un scope conversation permettant de faire ça. Apache CODI l’étend en permettant de gérer des sous conversations (mise en pause d’une conversation, lancement d’une autre)

Agnès & Cédric : Puis-je définir facilement un workflow obligeant mon client à enchaîner plusieurs écrans pour une conversation donnée (le paiement par exemple)?

Loïc (Equipe Stateless): Pour gérer un workflow de navigation, il y a tout ce qu’il faut aujourd’hui dans les librairies côté client pour faire ça. On peut enregistrer les différentes étapes et y revenir avec l’history API HTML5 par exemple.

Antoine (Equipe Stateful): Concernant le worklfow, actuellement il existe à ma connaissance trois solutions stateful gérant ce besoin :

Si tout ça ne convient pas, on peut déjà faire deux ou trois trucs avec le fichier de navigation JSF, mais ce n’est pas vraiment une machine à état.

Agnès & Cédric : Comment sont classiquement démarquées vos transactions (base de données) au sein de vos applications? Quelle est dans la majeure partie des cas la durée de vie de la transaction ?

Loïc (Equipe Stateless): La durée de vie de la transaction est liée à celle du cycle de la requête HTTP : si une erreur survient lors du traitement d’une requête, tout ce qui s’est passé entre la demande du client et l’envoi de la réponse est annulé (rollback). C’est un moyen de rendre atomique chaque traitement lié à une requête. Il n’y a pas besoin d’utiliser un pattern du type open session in view, avec ce procédé on accède à nos objets (et mêmes aux éléments à charger en “lazy”) durant tout le traitement de la requête, quelle que soit la couche dans laquelle on se trouve.

Philippe (Equipe Stateless): ben je crois que Loïc a répondu à la question!

Antoine (Equipe Stateful): Par défaut la durée de vie d’une transaction est liée à la requête HTTP. L’utilisation de l’extended persistence context permet de retarder la transaction après plusieurs écrans (un wizard).

Agnès & Cédric : Comment une architecture (avec/sans) état, répond elle aux problématiques de scalabilité, et de reprise sur activité en cas de panne ?

Philippe (Equipe Stateless): Pas d’état conversationnel : le serveur ne conserve aucune information entre 2 requêtes différentes d’un même client, du coup la 1ère requête pourrait être traitée par un serveur A, la 2ème par un serveur B, etc. … Mon “identité” existe côté client uniquement, donc on pourrait même imaginer que le serveur soit coupé entre les 2 requêtes.
-> côté serveur : pas de mémoire utilisée pour les sessions -> pas de problème de synchronisation de sessions entre plusieurs serveurs.

Loïc (Equipe Stateless): Il est plus simple d’assurer la scalabilité avec une architecture sans état : rien n’est partagé entre les serveurs. Si on veut ajouter un serveur derrière notre loadbalancer pour monter en charge on évite ainsi tout le paramétrage lié aux sessions que l’on trouve avec les architectures stateful : mise en place d’un cache de session distribué, duplication de sessions ou encore affinité des utilisateurs à un seul serveur… Pour gérer les pannes c’est également plus simple, si on coupe un serveur, l’utilisateur pourra continuer sur un autre serveur sans qu’on ait à se demander comment il va récupérer l’état qu’il avait stocké sur le premier serveur.

Antoine (Equipe Stateful): En stateful, la scalabilité c’est le cluster, mais c’est un sujet très vaste et souvent regardé que du point de vue du serveur d’application et pas de la base de données. La tolérance de panne est également assurée par le cluster bien que l’architecture de l’application soit primordiale pour limiter la perte d’information lors du basculement. Le sujet de la résilience des applications est également vaste.

Agnès & Cédric pour l’équipe “Stateless” : commençons par une question naïve : Quelle est la bonne pratique pour gérer la sécurité de l’application ? Où est stocké l’état si nécessaire ? Purement en base de données, purement côté client ?

Philippe (Equipe Stateless): Différentes solutions, oauth (f… je ne sais pas le prononcer) openid, … Play est fourni avec une “basic authentication”, il suffit de passer en mode SSL pour “renforcer” la mécanique. On peut aussi utiliser une “digest authentication” dans ce cas là, il faut se faire sa propre mécanique ou utiliser openid.

Loïc (Equipe Stateless): L’état doit être stocké sur le client, cette information doit être de taille minimale (loggé ou pas + rôle de l’utilisateur). C’est ce qui se passe lorsque vous êtes loggés sur GMail par exemple. Ceci n’empêche pas le mécanisme d’authentification d’être robuste (ex : oAuth, https…). Pour rappel le cookie de session est signé et crypté.

Agnès & Cédric pour l’équipe “Stateful” : Est-ce simple de tester une webapp stateful ?
Antoine (Equipe Stateful): Aujourd’hui oui grâce à JBoss Arquillian. J’en ferais une démo lors de ma prez

Merci Antoine, Loïc et Philippe!

Les inscriptions pour leur session au Lyon JUG le 22 novembre sont ouvertes! Rendez-vous sur le site du Lyon JUG.

EJB 3.x – Lightweight killer apps but nothing more than Adam in action

Cet article présente la deuxième partie de la soirée Adam Bien au ParisJUG.

Après une présentation théorique des architectures et des EJBs puis un buffet animé par les discussions sur la présentation de première partie, Adam nous a montré la puissance de la plateforme JEE 6 et les EJB 3.x en réalisant du code en direct. Dans notre article précédent, on vous a parlé des approches d’architecture opposées SOA et DDD; dans celui-ci on traite en détail de la partie théorique des EJBs accompagnée des exemples d’Adam.

Allons-y avec la théorie et la pratique des EJBs !

Adam Bien - Photo: José Paumard

Comme on l’ a déjà évoqué précédemment, les EJBs d’aujourd’hui ne sont plus considérés comme une technologie lourde. Il sont simples, concis, et l’ancien mode de configuration par des tonnes de XML a été supplanté par les annotations en laissant au développeur la possibilité de changer la configuration par défaut avec le XML (le pattern “Convention over Configuration”).

Le conteneur des EJBs est maintenant très léger aussi, il pèse à peine 1Mo. Dans le profil Web on a  la possibilité de déployer le container avec notre application dans un war. Cela permet que tous les objets aient le même classloader, c’est qui est très pratique pour éviter des exceptions de type “class not found” dues au fait que les classes n”ont pas été chargées dans le même ClassLoader. JNDI est indépendant du serveur d’application, et on peut même faire du monitoring JMX aux EJBs.

Adam nous a dit que ses exemples sont “crappy” (En dehors de cette affirmation je pense qu’il est très modeste) et que le fait de tout mettre dans le même classloader n’est pas très élégant, mais très pratique.

 

EJB 3.x : légers, simples, testables

Le plus simple des EJBs :

@Stateless
public class ChampionService {
   public String sayWorldCupWinner(){}
}

Les EJBs d’aujourd’hui n’ont aucune contrainte d’héritage, on les crée à partir de simples POJOs. On revient ici à la question “interface” évoquée dans l’article précédent.  Lors du design, pensez à l’utilité réelle des interfaces.  Avec l’injection des dépendances, on peut utiliser l’implémentation d’un EJB sans passer forcément par une interface, et cet EJB sera testable avec la même simplicité.

Exemple de test avec le framework Mockito :

public class SimpleChampionServiceTest {
   @Test
   public void sayThisYearsWinner() {
      ChampionService service = mock (ChampionService.class);
      when(service.sayWorldCupWinner()).thenReturn("España");
      ServiceFacade facade = new ServiceFacade();
      facade.service = service;
      assertFalse(facade.isWinnerPaysBas());
   }
}
N.B. : Cet exemple n'a pas été développé par Adam Bien mais par Paul le poulpe,
qui réside en Allemagne  lui aussi. Merci Paul.

Singletons

JEE6 permet l’utilisation des EJBs à mode singletons. Pour cela, on annotera une classe comme @Singleton. L’annotation @Startup permet d’indiquer au conteneur de démarrer le singleton et sa méthode @PostConstruct au démarrage de l’application.

@Singleton
@Startup
public class StartMeUp {
     @PostConstruct
     public void initialization() {
     }
}

CDI – Context Dependency Injection

CDI – Injection des dépendances et contexte – comble les lacunes de l’injection de dépendances JEE5 . Entre autres limitations, avec JEE5 on n’avait pas la possibilité d’injecter un EJB dans un framework présentation non standard ou d’injecter une classe utilitaire qui n’était pas implémentée sous la forme d’EJB.

Création du HelloWorld

A l’aide des wizards de NetBeans, Adam a créé un projet de base pour ses exemples. NetBeans est livré avec un serveur Glassfish intégré et il semble plutôt bien pour réaliser des exercices d’apprentissage comme celui-ci. Il a utilisé la base de données Derby qui marche très bien aussi pour ce type d’utilisation.

Il a créé le package java.fr.jug.dechusse en l’honneur desJDuchess :D et l’EJB ParisJUGService.

@Staless
public class ParisJugService {
     public void helloParis(){
          System.out.println("Hello Paris");
     }
}

Un peu d’injection de dépendances pour appeler la méthode avec JSF 2 depuis le contrôleur :

@WebServlet(name="HelloController", urlPatterns={"/HelloController"})
public class HelloController extends HttpServlet {

    @EJB ParisJugService jugService;

    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        jugService.helloParis();
        try {
            out.println("<html>");
            out.println("<head>");
            out.println("<title>Servlet HelloController</title>");
            out.println("</head>");
            out.println("<body>");
            out.println("<h1>Servlet HelloController at " + jugService.helloParis() + "</h1>");
            out.println("</body>");
            out.println("</html>");
        } finally {
            out.close();
        }
    }

On a besoin d’un fichier nommé beans.xml dans le répertoire web WEB-INF. Cela indique que le projet est un module qui utilise les beans CDI. Le contenu du fichier est vide, mais on se servira de ce fichier pour ajouter la configuration XML qu’on ne souhaitera pas réaliser uniquement avec les annotations.

Après un tonnerre d’applaudissements de toute la salle pour ce HelloWorld :) on est passé aux sujets intéressants sur JEE6 qu’Adam avait traité lors de la partie théorique !

Interceptors

JEE6 permet le développement “lightweight” AOP (Programmation Orienté Aspects). AOP cherche à séparer ce qui est du code métier et de ce qui n’en est pas. On développe le code non fonctionnel – un aspect – et on le réutilise :  le code fonctionnel est ‘décoré’ avec la fonctionnalité de l’aspect en exécution.

Les aspects du JEEs’appellent “Interceptors”. Ils sont assez limités car ils ne sont optimisés que pour travailler avec les EJBs. Or, ils répondent aux besoins courants dela vaste majorité des applications réelles.

Dans l’exemple suivant, on configure un interceptor à partir des annotations ; on pourrait le faire aussi en XML. Chaque méthode de configuration a cependant ses avantages et ses inconvénients

  • Les annotations sont plus intrusives, mais elles permettent d’avoir le code plus documenté (on voit explicitement l’aspect) et rendent plus facile la factorisation et la maintenance. 
  • Le XML est moins intrusif et plus puissant avec des options de configuration supplémentaires, en contrepartie, il est plus difficile à maintenir, et il a quelque chose de “magique” (le code n’a aucun référence, et à terme ceci pourrait causer des soucis.

La règle générale est ici la même : pensez au vrai besoin pour trouver le meilleur compromis.

Voici l’interceptor crée par Adam :

public class CrossCutter {

    @AroundInvoke
    public Object cutMe(InvocationContext context) throws Exception{
        System.out.println("--- interceptor" + context.getMethod());
        return context.proceed();
    }

}

Voici comment utiliser l’interceptor. Il sera exécuté par toutes les méthodes de la classe :

@Stateless
@Interceptors(CrossCutter.class)
public class ParisJugService {

    public void helloParis(){
        System.out.println("Hello Paris ! ");
    }
}

Le résultat de l’appel à la méthode “helloParis” donnera la sortie suivante dans la console :

--- interceptor hello
Hello Paris !

Processus Asynchrone

JEE 6 permet facilement l’exécution de tâches en mode asynchrone. Dans l’exemple suivant développé par Adam, un EJB appelé Messenger contient une méthode annotée “Asyncronous” qui lance un message 2000 millisecondes après son invocation. La méthode répond avec un objet du type Future du JDK 6.

@Stateless
public class Messenger {

        public String message(){
            return "hello paris" + System.currentTimeMillis();
        }

        @Asynchronous
        public Future audit(String message){
            try {
               Thread.sleep(2000);
               System.out.println(" Audit: " + message);
            } catch (InterruptedException ex) {
               Logger.getLogger(Messenger.class.getName()).log(Level.SEVERE, null, ex);
            }
            return new AsyncResult("Done!");
        }
}

Dans l’EJB ParisJUGService, on injecte l’EJB Messenger pour l’utiliser.

@Stateless
[...]
public class ParisJugService { 
 @EJB
   Messenger messenger;

   public void helloParis(){
        System.out.println("Hello Paris");
        messenger.audit("something " + sc.getCallerPrincipal());
   }
}

Si on appelle la méthode helloParis N fois à la suite très rapidement, le message “Hello Paris” s’affichera dans la console à chaque appel, et le message d’audit s’affichera toutes les 2000 millisecondes. Vous constaterez qu’effectivement le code s’exécute en mode asynchrone. Sans le mode asynchrone, on n’aura pas de retour de la méthode ‘helloParis’ tant que l’appel à la méthode ‘audit’ n’est pas terminé.

Persistance de données

Adam nous a aussi montré un exemple de persistance des données avec JPA. D’abord il a créé une entité persistante à l’aide de l’annotation @Entity. Il a placé les annotations @Id et @GeneratedValue pour définir la clé primaire et la génération automatique des clés. Les propriétés name et description font aussi partie des propriétés persistantes. Ceci est la configuration la plus simple d’une entité JPA.

@Entity
public class SessionEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private String name;
    private String description;

    public SessionEntity() {
    }

    public SessionEntity(String name) {
        this.name = name;
    }
}

Dans l’EJB ParisJUGService, il a injecté avec l’annotation @PersistentContext l’EntityManager. L’appel à laméthode “persist” a effectivement écrit l’objet dans la base de données Derby.

@Stateless
[...]
public class ParisJugService { @PersistenceContext EntityManager em;

    public void helloParis(){
        System.out.println("Hello Paris");
        em.persist(new SessionEntity("hopefuly works"));
    }
   [...]
}

Configuration XML : il nous faut le fichier “persistence.xml” dans le classpath. Le fichier est très simple.

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
                  http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
  <persistence-unit name="ParisJugMgrPU" transaction-type="JTA">
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
    <jta-data-source>jdbc/sample</jta-data-source>
    <properties>
      <property name="eclipselink.ddl-generation" value="drop-and-create-tables"/>
    </properties>
  </persistence-unit>
</persistence>

Événements

Avec JEE6 nous avons la possibilité de créer assez facilement des événements. Ainsi, depuis la classe ParisJugService, on injecte un objet “Event” et on lance un événement :

@Stateless
[...]
public class ParisJugService { 
 @Inject Event<String> event;

   public void helloParis(){
        System.out.println("Hello Paris");
        event.fire("hello Paris invoked!");
   }
}

Une méthode d’un EJB est capable d’écouter (observer) cet événement :

@Stateless
public class EventReceiver {

    public void onHelloParis(@Observes String message){
        System.out.println("----------- " + message);
    }
}

REST

Pour terminer (on aurait pu rester toute la nuit), Adam nous a montré comment faire un peu de REST avec JAX-RS. D’abord, on ajoute l’annotation @Path à l’EJB ParisJUGService, puis les annotations @GET et @Produces à la méthode helloParis.

@Path("session")
@Stateless
public class ParisJugService {
    [...]

 @GET
 @Produces({MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML})
     public Session helloParis(){
          [...]
          return new Session(messenger.message() + " " + tl.hello() )
     }
}

L’annotation @Produces définit les formats que le client pourra utiliser pour recevoir l’objet Session : JSON, XML, etc.

L’appel à la méthode on la fait via HTTP/GET http://url/session

Conclusions

Adam nous a vraiment donné l’envie d’utiliser la plateforme JEE6. La possibilité de déployer juste un war, les interceptors, les singletons, “la disparition” des interfaces …  En bref et en revenant au titre de la conférence : grâce à la nature LIGHTWEIGHT de la plateforme, on peut réaliser des applications de grande échelle mais tout aussi bien des applications de petite taille.
Merci Adam pour tes conférences, tes conseils, tes publications et pour être venu à Paris !

 

DDD vs SOA – Lightweight killer apps with nothing but vanilla Java EE 6

Adam Bien est venu présenter sa vision de l’architecture Java EE lors de la session de Juillet du Paris JUG. Ce premier article présente la première partie de la soirée, plutôt dédiée aux concepts et à la théorie.

Adam Bien - Photo: Claude Falguière

Les applications développées sous la plateforme JEE 6 sont maintenant très légères. On est loin de l’ancienne affirmation “les EJBs sont très lourds” ; celle-ci fait désormais partie du passé. Adam Bien a démontré la puissance de la plateforme et il nous a donné envie de la réapprendre, surtout avec la deuxième partie de la conférence qui a été entièrement pratique comme il nous l’avait promis. Le niveau du contenu théorique a été assez avancé. Nous vous conseillons la lecture, ou relecture rapide, de l’article précédentAdam Bien / JEE6 / Architecture – où vous est présenté Adam et dans lequel on vous plonge dans le contexte; ensuite vous pourrez repasser à cette partie plus détaillée qui s’appuie sur les concepts déjà traités.

Commençons par la théorie des architectures !

Lightweight Killer Applications

Grâce aux design patterns comme “Convention over Configuration”, l’injection de dépendances et les annotations, l’architecture des applications JEE6 est considérée LIGHTWEIGHT ! Que signifie “lightweight” ? Lightweight indique que l’architecture est rapide, simple, petite, légère, “facile”, lean (maigre) et qu’elle facilite le développement itératif et incrémental des applications d’entreprise.

Notez que le mot facile se trouve entre guillemets : Attention ! On peut mettre en péril la réussite des projets si on  sous-estime les difficultés et challenges lors du design et de l’implémentation sous JEE6. Comme on l’avait déjà évoqué dans notre article précèdent, afin de répondre aux besoins réels des applications d’entreprise, on nous propose deux approches d’architecture opposées :

  • Architecture pilotée par le Service (SOA – Service Oriented Architecture ≈ SOAP)
  • Architecture pilotée par le Domaine (DDD – Domain Driven Design ≈ REST)

Adam utilise l’acronyme SOA afin de faciliter la compréhension, mais il a aussi souhaité faire la distinction en utilisant les termes “Design Piloté par le Service” car le concept SOA a un sens encore plus large. Concept apparu après l’EAI (“Enterprise Application Integration”), le SOA essaie de répondre aux besoins d’intégration et d’architecture au sens global. Avec le SOA on regarde le système d’information d’une entreprise comme un groupe de services au lieu de un groupe d’applications comme avec son précurseur EAI. Il existe aussi une nouvelle approche, ROA (Ressource Oriented Architecture), qui nous parle d’un vision ressource.  Mais au delà des concepts, il faut du travail pour la réalisation des applications !

Les deux types architectures décrits par Adam – DDD et SOA – sont des designs que l’on peut choisir pour développer les applications, et les deux s’appuient sur le pattern ECB comme l’on va voir ci-après.  Le pattern ECB existe depuis longtemps et il est indépendant de la plateforme JEE6 (ce n’est pas un pré-requis).

ECB – Entity Control Boundary Pattern

Similaire au pattern MCV (Model View Contrôler), il n’est pas consacré qu’à la couche présentation. Il est composé de trois éléments : Entity, Control et Boundary

.

Entity Control Boundary pattern

‘Entity’ : Élément persistent et passif (il a besoin d’un contexte d’exécution pour fonctionner) qui contient non seulement les données persistantes mais également une partie de la logique métier.

‘Control’ : Élément orchestrateur qui implémente un scénario donné. Il orchestre les entités pour récréer un scénario fonctionnel particulier, mais la logique métier propre à chaque type d’entité reste encapsulée dans l’entité.

‘Boundary’ : Élément qui se trouve en périphérie du système ou sous-système et s’occupe de la communication. Certains Boundarys s’occupent de l’entrée au système depuis l’extérieur (front-end) ; les autres fournissent la sortie (back-end).

Sur ce point, se pose une question importante : Avez-vous compté le nombre de couches ? Il y en a deux. La couche “Boundary”, et la couche “Business” qui contient les éléments de contrôle et les entités.

Où est la couche DAO ? A-t-elle disparu ?

Oui, la couche DAO a disparu pour les opérations CRUD, mais elle sera encore là. Pourquoi ? La réalité est qu’on aura besoin des DAO dans la plupart des applications afin de respecter le principe DRY (Don’t Repeat Yourself) et la séparation des responsabilités. Une application classique réalise les mêmes opérations constamment. Sans un DAO dédié, les queries répétées seront arrosées par toute la couche business et cette duplication du code réduira considérablement la maintenance.

Pour bien expliquer ce point : il s’agit simplement de ne  plus jamais créer les DAO par défaut et uniquement parce que ce design pattern du catalogue J2EE le dit. Le pattern DAO n’est plus considéré la meilleure pratique à mettre en place. Aujourd’hui on va plutôt travailler en refactoring : Identifier le code dupliqué dans la couche business pour après le factoriser dans un DAO. Sans duplication de code,  mieux vaut déléguer directement à l’EntityManager depuis la couche business. Une couche DAO sans un vrai besoin augmentera l’effort de maintenance (plus de code, plus de tests) sans apporter une réelle valeur ajoutée.

Grâce aux generics, à partir du JDK 5 nous pouvons utiliser une couche DAO générale et très puissante qui fournira une API transverse aux applications. Ainsi, pour vous illustrer cela avec un peu de code :

@Stateless
@Local(CrudService.class)
@TransactionAttribute(TransactionAttributeType.MANDATORY)
public class CrudServiceBean implements CrudService {

    @PersistenceContext
    EntityManager em;

    public  T create(T t) {
        this.em.persist(t);
        this.em.flush();
        this.em.refresh(t);
        return t;
    }

    @SuppressWarnings("unchecked")
    public  T find(ClLibraryass type,Object id) {
       return (T) this.em.find(type, id);
    }

    public void delete(Object t) {
       Object ref = this.em.getReference(t.getClass(), t);
       this.em.remove(ref);
    }

    public  T update(T t) {
        return (T)this.em.merge(t);
    }

    public List findWithNamedQuery(String namedQueryName){
        return this.em.createNamedQuery(namedQueryName).getResultList();
    }

   [...] 

}

Dans ce code on voit un Service DAO qui est implémenté par un EJB @Local et @Stateless. On injecte le contexte persistent (@PersistentContext) et EntityManager. On utilise les génériques <T> pour factoriser le code qui est commun à n’importe quelle entité. CrudService est l’interface qui sera exposé au client.

L’utilisation des interfaces

Comme on verra dans notre article suivant, l’utilisation des interfaces avec les EJBs n’est plus obligatoire. Dans ce point de la conférence, un débat a commencé : Est-il une bonne pratique le développement Interface + Implémentation ? Réaliser systématiquement une implémentation interface + classe ajoutera des fichiers à maintenir, et rendra l’application moins légère et l’API plus complexe. L’idée d’une interface est d’exposer une API et cacher l’implémentation. Par conséquent, si une classe ne changera pas d’implémentation, l’utilisation des interfaces n’apportera aucune valeur. Si l’API ne sera jamais exposé au client, non plus. Sur ce point, lors de la partie questions/réponses, deux bonnes pratiques ont été évoquées :

  • d’une part de différencier l’API externe (exposée au client) de l’API qui restera interne,
  • d’autre part d’identifier les objets avec le même comportement et une implémentation différente.

Aussi l’usage de designs patterns comme “Strategy” imposent l’utilisation des interfaces. Ensuite, avec ECB en tête, Adam est passé à l’implémentation de deux approches opposées : l’architecture pilotée par le domaine et l’architecture pilotée par le Service.

DDD vs SOA : Domaine ou Service

Comme vous pouvez constater dans l’image, les deux approches basent leur architecture sur le pattern ECB. SOa vs DDD

Afin de ne pas répéter notre article précèdent, et d’expliquer facilement le diagramme, voici un tableau récapitulatif.

Piloté par le Domaine vs Piloté par le service

DDD (Domain Driven Design) SOA (Service Driven Design)
Principal Domaine (Entity) Service (Control)
Programmation Cherche l’orientation objet pure Approche procédural
ECB – Entity PDO – Persistent Domain Objet. Contient du logique métier. Les entités ont leur état encapsulé et un comportement bien précis (true objects) Anemic Object Model – Structure de données sans comportement qui expose son état à partir des modificateurs (get/set). Ne contient aucun logique métier
ECB – Control Ne contient quasiment pas de logique métier. Très léger, parfois inexistant. Implémente toute le logique métier.
ECB – Boundary : Gateway – Expose et manage les entités (PDO). Nature Stateful (EJB @Stateful) Façade – Cache les entités derrière les services. Nature Stateless (EJB @Stateless)
Nombre de couches : 2 couches, pas besoin de DTO (Data Transfert Object) plus de 2 couches. besoin de DTO (Data Transfert Object)
La couche DAO : utilise la stratégie décrite précédemment utilise la stratégie décrite précédemment
S’intègre bien avec : REST SOAP

La vaste majorité des application J2EE / JEE existantes ont été développées avec l’approche procédural d’orientation au service. Avec les EJBs 2.x, penser à l’approche DDD n’était pas seulement une aberration, mais était quasiment impossible due à la complexité.

Conclusions

Les deux architectures opposées sont des meilleures pratiques dans des contextes particuliers. Ne soyons pas sectaires et restons ouverts aux deux approches. Dans la pratique, la plupart des projets du monde réel auront besoin d’une architecture mixte.

Adam Bien - Photo: José Paumard

Adam a voulu nous transmettre un message aussi important que l’effet de connaître les frameworks du marché et les design patterns.

« Pensez toujours au vrai besoin, au contexte et à la valeur ajoutée »

Une architecture en 5 couches dans la pratique n’apportera aucune valeur si notre application reste monolithique.  Grâce aux nouveautés de JEE 5 et 6, on peut réaliser des applications beaucoup plus légères qui répondront au vrai besoin. Rappelons-nous qu’on n’applique pas les designs patterns pour le plaisir, mais pour répondre au besoin et pour obtenir une valeur ajoutée.

« Rester petit mais penser grand »

Lorsqu’on est confronté à la réalisation d’une architecture, il est très important de bien identifier les cas d’évolutions probables auxquels l’application sera sujette. Dans ce contexte, on ne doit cependant pas réaliser le design d’une architecture en assurant toutes les possibilités d’évolution pour anticiper tous les besoins possibles, auquel cas on risque de rester éternellement dans la phase « design » sans en réaliser le développement. En anticipant seulement les besoins les plus probables on pense grand, tout en restant petit. Une second article est dédié aux démonstrations de code de la deuxième partie de soirée.

Pratique – EJB 3.x et Adam en action

 

Soirée Adam Bien au Paris JUG (06/07)

Le mardi 6 Juillet est le dernier Paris JUG avant la rentrée. Pour cette occasion, on compte sur la présence d’un speaker d’excellence : Adam Bien. Il va nous présenter deux architectures opposées – Lean Service Oriented Architecture (SOA) et Domain Driven Architecture – ainsi que la façon dont on les implémente sous la plateforme JEE 6 grâce aux EJB 3.

Histoire de vous mettre l’eau à la bouche, je vais vous présenter rapidement Adam Bien et les sujets qui seront traités plus en détail, argumentés, et accompagnés d’exemples pratiques et de retours d’expérience le mardi 6 juillet au Paris JUG.

Une conférence à laquelle assister absolument !!

Qui est Adam Bien ?

Adam Bien est un consultant indépendant, formateur Java, architecte du software et développeur qui  implémente des architectures Java à grande échelle au sein des entreprises allemandes.

Nommé Java Champion en Janvier 2007,  il est membre de NetBeans Dream Team, de Sun Advantage Partner, Glassfish System Integrator, du groupe d’experts Java Community Process (EJB 3.1, JPA 2.0, Java EE 6) et il est fortement impliqué dans les technologies Cloud, Grid et P2P. Actuellement, il travaille en parallèle comme architecte et développeur au sein de plusieurs projets d’architecture J2EE/Java EE 5/MDA et au sein des architectures EAI basés en composants pour Java EE et .Net.

Il est aussi connu pour ses nombreux articles et livres publiés dans le cadre Java/J2EE/J EE et l’architecture distribuée. Parmi ses livres, on peut trouver plusieurs ouvrages en allemand (“Enterprise Architekturen”, “Java EE 5 Architeckturen”, “Struts” etc. ) ainsi que son dernier livre publié en 2009 et écrit en anglais : “Real World Java EE patterns” où il explore les défis de Cloud Computing.

EJB3 légers et pouvoir des annotations

Depuis des années, les EJB ont toujours été identifiés comme une technologie trop lourde. Effectivement, jusqu’à la version EJB 2 cette réputation était justifiée. Mais depuis la version EJB 3 tout a changé et on peut affirmer à présent que les EJB sont très légers. Ils sont configurés par annotation (non par de tonnes de XML), intégrés avec JPA (Java Persistence API), scalables au sein des machines multicore et avec multiples CPU, et constituent une solution standard et portable pour les applications métiers d’entreprise.

“Convention over configuration”

Le principe du design pattern “Convention over configuration” est le suivant : Les applications se basent sur des conventions au lieu de se baser sur la configuration. Ainsi, elles chercheront à réduire le nombre de fichiers de configuration, fourniront une configuration par défaut (convention par règle de nommage) mais permettront aussi la substitution des valeurs par défaut via la configuration (à partir des fichiers ou une autre source de données).

La mise en place de ce pattern passe par l’utilisation des annotations. Les EJB 3 ont toujours besoin de la même quantité d’information pour fonctionner. Cette information étant la même dans 80% des cas, il suffit, par exemple, de placer l’annotation @Stateless sur une classe POJO (Plain Old Java Object) pour lui donner le comportement de base d’une entité de session.

Injection de dépendances

Il s’agit de retirer des objets la gestion des dépendances entre les objets et de la confier à un conteneur, le conteneur des EJBs dans ce cas.  Ainsi, pour utiliser une instance EJB, on se servira de l’annotation @EJB pour l’injecter, pour utiliser une ressource (JMS, Datasource) on utilisera l’annotation @Ressource etc.

ex : Voici un EJB qui “injecte” un autre EJB de service. Le conteneur des EJBs s’occupe de chercher l’instance du Service pour que le client puisse l’utiliser.

@Stateless
public class ClientBean implements Client {
     @EJB
     private Service service;

     public String sayHello() {
          return this.service.getMessage();
     }
}

La plateforme JEE 6 permet grâce aux EJBs d’implémenter deux approches d’architecture opposées :

  • Lean Service Oriented Architecture (SOA) – Architecture légère Orientée au Service
  • Domain Driven Architectue – Architecture pilotée par le Domaine

Approche 1 : Lean Service Oriented Architecture (SOA)

Dans le modèle d’architecture SOA, comme son nom l’indique, l’entité la plus importante est le Service. On peut considérer un service comme un contrat, un use case, même un story, qui exécute une ou plusieurs opérations (transactions). Le principe est de l’exposer au système d’information et d’encapsuler non seulement son implémentation mais aussi sa localisation.

Interfaces et packages

Les bases d’une implémentation avec Java/JEE sont les interfaces et les packages. La fonctionnalité d’un package est exposée via une interface (parfois par plusieurs). On définira d’abord les interfaces des services à exposer, pour ensuite créer les classes qui implémenteront leur logique métier.

Diviser les responsabilités – “divide and conquer”- facilite la réutilisabilité et améliore la maintenance du code. Ainsi, sans trop détailler :

  • Une classe annotée @Stateless et @Remote servira de façade. Cet EJB fournira le contrôle d’accès aux services, ainsi que le comportement transactionnel; il implémentera l’interface à exposer.
  • Une classe annotée @Stateless et @Local servira de service. Cet EJB implémentera le métier et ne sera accessible qu’à partir de la façade.

Les annotations des EJBs seront placées sur la classe d’implémentation et jamais sur l’interface; ainsi, les services exposés sont indépendants de l’API EJB et leur implémentation est complètement encapsulée.

Les objets du domaine

Si les façades implémentent la logique d’accès et les services la logique métier, il ne reste plus grand chose aux objets du domaine. Ils encapsulent un état mais n’ont  aucune logique métier. Les entités JPA sont des classes annotées @Entity qui contiennent des attributs, des accesseurs (getter/setter) et c’est tout. Ce pattern (même considéré un anti-pattern par les puristes de la POO) est connu sous le nom “Anemic Object Model” et colle parfaitement avec les besoins de SOA.

La majorité des applications d’entreprise J2EE/ J EE d’aujourd’hui sont proches de l’architecture décrite précédemment. Néanmoins, elle convient parfaitement jusqu’au moment où le comportement dépend du type des objets. L’implémentation des services utilise alors des instructions du type “instanceof” ou encore des blocs“if/else” et “case” pour s’y adapter. Ceci est la conséquence directe du  “Anemic Object Model” qui déplace le contrôle en dehors des entités au détriment des services et façades où se trouve la vrai logique métier.

Approche 2 : Domain Driven Architecture Design

L’architecture pilotée par le domaine est basée sur l’utilisation de vrais objets (true objects). Ces objets encapsulent leur état et fournissent également des  comportements, bien définis en fonction du type.

PDO

Les objets du domaine sont le socle de l’application. Ils gèrent leur état,  la persistance de leur état et implémentent la logique métier. Il arrive même dans certains cas que l’on n’ait pas besoin d’utiliser de service.

Les entités PDO (Persistent Domain Object) sont persistantes. Ainsi, chaque changement, au niveau de leur état ou de leurs relations, sera automatiquement synchronisé avec le moteur de persistance à la fin de la transaction. Ils seront exposés publiquement; cela oblige le concepteur à bien réfléchir à l’API qui sera fournie au client.

Gateways

Les PDO sont passifs et ne démarquent pas de transactions ; ils ont besoin d’un contexte d’exécution pour fonctionner.

Cela va nous poser un  problème à cause de la nature stateless des applications Java EE : après l’invocation d’une méthode transactionnelle, via un service ou un service façade, toutes les entités JPA – les PDO – sont détachées. Le client perd le contexte transactionnel; on est constamment obligé de transporter et de “merger” tout le contexte entre le client et le serveur avec les difficultés que cela implique.

Solution: Créer un “anti service façade” – un gateway. On ne cache plus les entités derrière une façade, on les expose  le plus possible aux couches supérieures telles que la couche Présentation et on permet à ces couches de les modifier directement . Cette stratégie, contradictoire avec les principes J2EE classiques sur la maintenance, semble dans certains cas plus pratique dans les projets du monde réel. Il s’agit tout simplement de se débarrasser des couches inutiles et d’exposer la couche domaine à la couche présentation. Chaque changement du domaine est directement visible depuis l’IHM.

Une gateway est implémentée par une classe annotée @Stateful et @Local – un EJB – qui manage aussi les transactions et contient l’EntityManager et le contexte persistent.

Conclusion

Ce qui est une bonne pratique chez l’un est un anti-pattern chez l’autre. Or, les deux approches opposées sont applicables, parfois complémentaires et nécessaires.

Java EE 6 et les EJBs permettent les deux types d’implémentations. Un point à  noter, l’approche SOA semble avoir une bonne affinité avec SOAP et les WebServices. Par contre, l’approche Domaine semble mieux s’accorder avec des architectures de type REST qui est focalisé sur une manipulation directe des ressources.

Des démos, du code et toutes les réponses à vos questions, directement adressées à Adam… 

dans le prochain Paris JUG !!

Inscrivez-vous !!

Les inscriptions ouvriront Jeudi 1er le matin. Soyez prêtes, ces temps-ci les place partent très vite.  Si vous voulez recevoir la notification de l’ouverture par e-mail jeudi matin pour pouvez vous abonner à la mailing list Annonces du JUG.

Les sources utilisées pour cet article sont les suivantes :

Il arrive même dans certains cas que l’on ait pas besoin d’utiliser de service

En continuant à utiliser le site, vous acceptez l’utilisation des cookies. Plus d’informations

Les paramètres des cookies sur ce site sont définis sur « accepter les cookies » pour vous offrir la meilleure expérience de navigation possible. Si vous continuez à utiliser ce site sans changer vos paramètres de cookies ou si vous cliquez sur "Accepter" ci-dessous, vous consentez à cela.

Fermer