NFP111 — Systèmes et Applications Réparties 1 de 48 Plan Objectifs de la norme 3.0 Un premier exemple NFP111 — Systèmes et Applications Réparties Cours 15 - Les Enterprise Java Beans (La norme 3.0) Cycle de vie Beans sessions Claude Duvallet Beans sessions sans état Beans sessions avec état Beans messages Beans entités Université du Havre UFR Sciences et Techniques 25 rue Philippe Lebon - BP 540 76058 LE HAVRE CEDEX Courriel : [email protected] http://litis.univ-lehavre.fr/∼duvallet/ NFP111 — Systèmes et Applications Réparties Plan La norme 3.0 Objectifs de la norme 3.0 1 Objectifs de la norme 3.0 2 Un premier exemple 3 Cycle de vie 4 Beans sessions 5 Beans messages 6 Beans entités Un premier exemple Cycle de vie Beans sessions Beans sessions sans état Beans sessions avec état Beans messages Beans entités 2 de 48 NFP111 — Systèmes et Applications Réparties Plan La norme 3.0 Objectifs de la norme 3.0 1 Objectifs de la norme 3.0 2 Un premier exemple 3 Cycle de vie 4 Beans sessions 5 Beans messages 6 Beans entités Un premier exemple Cycle de vie Beans sessions Beans sessions sans état Beans sessions avec état Beans messages Beans entités 2 de 48 NFP111 — Systèmes et Applications Réparties Plan La norme 3.0 Objectifs de la norme 3.0 1 Objectifs de la norme 3.0 2 Un premier exemple 3 Cycle de vie 4 Beans sessions 5 Beans messages 6 Beans entités Un premier exemple Cycle de vie Beans sessions Beans sessions sans état Beans sessions avec état Beans messages Beans entités 2 de 48 NFP111 — Systèmes et Applications Réparties Plan La norme 3.0 Objectifs de la norme 3.0 1 Objectifs de la norme 3.0 2 Un premier exemple 3 Cycle de vie 4 Beans sessions 5 Beans messages 6 Beans entités Un premier exemple Cycle de vie Beans sessions Beans sessions sans état Beans sessions avec état Beans messages Beans entités 2 de 48 NFP111 — Systèmes et Applications Réparties Plan La norme 3.0 Objectifs de la norme 3.0 1 Objectifs de la norme 3.0 2 Un premier exemple 3 Cycle de vie 4 Beans sessions 5 Beans messages 6 Beans entités Un premier exemple Cycle de vie Beans sessions Beans sessions sans état Beans sessions avec état Beans messages Beans entités 2 de 48 NFP111 — Systèmes et Applications Réparties Plan La norme 3.0 Objectifs de la norme 3.0 1 Objectifs de la norme 3.0 2 Un premier exemple 3 Cycle de vie 4 Beans sessions 5 Beans messages 6 Beans entités Un premier exemple Cycle de vie Beans sessions Beans sessions sans état Beans sessions avec état Beans messages Beans entités 2 de 48 NFP111 — Systèmes et Applications Réparties 3 de 48 Plan Introduction Objectifs de la norme 3.0 Un premier exemple Cycle de vie Beans sessions Beans sessions sans état Beans sessions avec état Beans messages Beans entités La norme EJB 3.0 constitue une évolution importante dans le domaine des EJB. Elle constitue une partie importante de la norme Java 2 EE 5. Un nouveau modèle de gestion de la persistance des données inspiré d’Hibernate de Jboss. Une simplification très importante des développements. Utilisation des annotations introduites dans la version 5.0 du langage Java. Adoption du modèle de programmation POJO. Suppression des descripteurs de déploiement. Suppression des interfaces métiers et des interfaces Home. La norme EJB 3.0 intègre aussi une approche Programmation Orientée Aspect (AOP) en introduisant la notion d’intercepteur (Interceptor). NFP111 — Systèmes et Applications Réparties 4 de 48 Plan Objectifs de la norme 3.0 Objectifs de la norme 3.0 Un premier exemple Cycle de vie Beans sessions Beans sessions sans état Beans sessions avec état Beans messages Beans entités Simplification de la conception des Beans coté développeur. Simplification de la définition des interfaces, suppression d’un certain nombre de pré-requis présents dans la norme 2.1 (absence d’héritage de super classes ou interfaces). Simplification de la création du Bean. Simplification des API pour l’accès à l’environnement du Bean : définition par simple injection dépendante. Introduction des annotations en Java en lieu et place du descripteur de déploiement. Simplification concernant la persistance d’objet par l’utilisation facilitée de mapping objet/relationnel basée sur l’utilisation directe de classes Java et non de composants persistants. NFP111 — Systèmes et Applications Réparties 5 de 48 Plan Les annotations Objectifs de la norme 3.0 Un premier exemple Métadonnées permettant à certains outils de générer des constructions additionnelles à la compilation ou à l’exécution. Cycle de vie Elles simplifient considérablement l’écriture de programmes. Beans sessions Beans sessions sans état Beans sessions avec état Beans messages Beans entités Elles permettent de se passer du descripteur de déploiement. Néanmoins, il est toujours possible de l’utiliser. Elle permettent de spécifier les interfaces locales ou distantes du Bean avec uniquement les mots clefs "@Remote" et "@Local". Elle permettent de définir un Bean session avec ou sans état avec uniquement les mots clefs "@Statefull" ou "@Stateless". NFP111 — Systèmes et Applications Réparties 6 de 48 Plan Hello World avec les EJB 3.0 (1/4) Objectifs de la norme 3.0 Un premier exemple Cycle de vie Beans sessions Beans sessions sans état Beans sessions avec état Beans messages Beans entités Définition de l’interface Hello : Désormais, cette interface est la seule à définir. Interface extrêmement simplifiée : pas besoins d’avoir recours à de quelconques héritages. package hello; public interface Hello { public String hello (String msg); } NFP111 — Systèmes et Applications Réparties 7 de 48 Plan Hello World avec les EJB 3.0 (2/4) Objectifs de la norme 3.0 Un premier exemple Cycle de vie Beans sessions Beans sessions sans état Beans sessions avec état Définition du Bean : Cette classe est aussi très simplifiée. Elle n’hérite pas de classes spécifiques. Elle doit pallier à la suppression des interfaces distantes et locales en utilisant des annotations. On utilise une annotation pour spécifier qu’il s’agit d’un bean Session sans état. Beans messages package hello; Beans entités import javax.ejb.*; @Stateless @Remote (Hello.class) public class HelloBean implements Hello { public String hello (String msg){ System.out.println ("Message reçu : "+msg); return "Hello "+msg; } } NFP111 — Systèmes et Applications Réparties 8 de 48 Plan Hello World avec les EJB 3.0 (3/4) Objectifs de la norme 3.0 Un premier exemple Cycle de vie Définition du descripteur de déploiement : il n’en reste presque rien ce qui simplifie son écriture Beans sessions Beans sessions sans état <?xml version="1.0" encoding="ISO-8859-1"?> Beans sessions avec état Beans messages Beans entités <ejb-jar xmlns="http://java.sun.com/xmlns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/ejb-jar_3_0.xsd" version="3.0"> <enterprise-beans> </enterprise-beans> </ejb-jar> NFP111 — Systèmes et Applications Réparties 9 de 48 Plan Hello World avec les EJB 3.0 (4/4) Objectifs de la norme 3.0 Définition du client : lui aussi est simplifié par rapport au même client dans les EJB 2.1. Un premier exemple Cycle de vie Beans sessions import import import import javax.naming.Context; javax.naming.InitialContext; hello.*; java.util.*; Beans sessions sans état Beans sessions avec état Beans messages Beans entités public class HelloClient{ public static void main(String[] args) throws Exception { Properties props = System.getProperties(); props.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory"); props.put(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces"); props.put(Context.PROVIDER_URL, "jnp://localhost:1099"); Context ctx = new InitialContext(props); Hello hello = (Hello) ctx.lookup("HelloBean/remote"); System.out.println(hello.hello("World")); } } NFP111 — Systèmes et Applications Réparties 10 de 48 Plan Cycle de vie des Beans 3.0 (1/3) Objectifs de la norme 3.0 Un premier exemple Cycle de vie Beans sessions Beans sessions sans état Beans sessions avec état Beans messages Beans entités Disparition des interface Home : les références sur les beans se font directement. Utilisation des méthodes "callback" pour la gestion du cycle de vie. Les méthodes callback peuvent être définies : soit directement dans le bean : la signature de la méthode doit être public void nom_methode (), soit dans une classe Listener Callback qui ressemble à une interface home. La classe Listener Callback : toutes les méthodes sont définies dans la classe. les méthodes prennent en argument le bean correspondant. il suffit d’importer cette classe dans la classe du bean CallbackListener. la signature de la méthode doit être public void nom_methode (Object) où Object est le type du bean, NomDeLaClasseCallback. NFP111 — Systèmes et Applications Réparties 11 de 48 Plan Cycle de vie des Beans 3.0 (2/3) Objectifs de la norme 3.0 Un premier exemple Cycle de vie Beans sessions Beans sessions sans état Beans sessions avec état Beans messages Beans entités Les méthodes "callback" doivent être annotées avec les annotations de callback : @CallBackListener(String classname) @PostConstruct @PreDestroy @PostActivate @PrePassivate @EntityListener(String classname) @PrePersist @PostPersist @PreRemove @PostRemove @PreUpdate @PostLoad Exemple 1 : Définition des méthodes "callback" directement dans le bean. @Stateful public class MonBean { private float total; private Vector productCodes; public int desMethods(){...}; ... @PreDestroy uneMethodeCallback() {...}; ... } NFP111 — Systèmes et Applications Réparties 12 de 48 Plan Cycle de vie des Beans 3.0 (3/3) Objectifs de la norme 3.0 Un premier exemple Cycle de vie Exemple 2 : Définition des méthodes "callback" en dehors du bean. Tout d’abord, on définit une classe Listener qui contiendra les méthodes "callback". Beans sessions Beans sessions sans état Beans sessions avec état Beans messages Beans entités public class MonBeanListener { @PreDestroy uneMethodeCallback() {...}; ... } Puis, on fait appel au "callback listener" dans le bean. @CallbackListener MonBeanListener @Stateful public class MonBean { private float total; private Vector productCodes; public int desMethods(){...}; ... } NFP111 — Systèmes et Applications Réparties 13 de 48 Plan L’injection de dépendance (1/2) Objectifs de la norme 3.0 Un premier exemple Cycle de vie Beans sessions Beans sessions sans état Beans sessions avec état Beans messages Beans entités Elle permet à un bean d’acquérir des références sur d’autres ressources ou d’autres objets de l’application. Auparavant, il fallait avoir recours aux fichiers XML (avec ejb-ref) et se servir du JNDI pour accéder à une ressource : Pour accéder à un EJB, il était obligatoire de passer par son interface Home pour récupérer l’interface et utiliser ses méthodes métiers. Maintenant, c’est le conteneur qui injecte ces références avant que toute méthode liée au cycle de vie de l’EJB ou méthode métier ne soit appelée. Le conteneur se charge d’initialiser toutes les ressources dont le bean a besoin. NFP111 — Systèmes et Applications Réparties 14 de 48 Plan L’injection de dépendance (2/2) Objectifs de la norme 3.0 Un premier exemple Cycle de vie Beans sessions Beans sessions sans état Exemple de récupération d’une ressource de type base de données : // On récupère une ressource maBD et on l’affecte à clientBD // Le type de maBD est déduit de la variable clientBD @Ressource (name="maBD") public SourceDesDonnees clientBD; Exemple de récupération de la référence d’un autre EJB : Beans sessions avec état Beans messages Beans entités @EJB public AddressHome addressHome; On peut aussi passer par les méthodes set... pour récupérer une ressource : // récupère la ressource de nom clientBD et de type SourceDesDonnees @Ressource(name="clientBD") public void setSourceDesDonnees(SourceDesDonnees clientBD){ this.sdd = clientBD; } // récupère la ressource de nom maBD et de type SourceDesDonnees @Ressource public void setClientBD(SourceDesDonnees maBD){ this.clientBD = maBD; } NFP111 — Systèmes et Applications Réparties 15 de 48 Plan Les méthodes d’interception Objectifs de la norme 3.0 Un premier exemple Cycle de vie Beans sessions Beans sessions sans état Beans sessions avec état Beans messages Beans entités Appelées méthodes "interceptors", elles seront exécutées à chaque appel d’une méthode métier définissant ces méthodes. Elles sont de la forme : public Object <methodName>(javax.ejb.InvocationContext) throws Exception Toute méthode interceptor doit prendre en argument l’interface suivante : public interface InvocationContext { // retourne le bean cible de la méthode interceptor public Object getTarget (); // retourne la méthode déclenchant l’interceptor public Method getMethod (); // retourne les paramètres de la méthode métier public Object[] getParameters(); public void setParameters (Object[] params); public java.util.Map<String, Object> getContextData(); // exécute la méthode interceptor suivante ou // la méthode annotée @AroundInvoke public Object proceed() throws Exception; } NFP111 — Systèmes et Applications Réparties 16 de 48 Plan Exemple de méthodes interceptor Objectifs de la norme 3.0 Un premier exemple Cycle de vie Beans sessions Beans sessions sans état Beans sessions avec état Beans messages Beans entités @Stateless @Interceptor("TestInterceptor") public class LoginBean { @AroundInvoke public Object testInterceptor (InvocationContext invContext) throw Exception { invContext.proceed (); } } public class TestInterceptor { @AroundInvoke public Object myInterceptor (InvocationContext invContext) throws Exception{ invContext.proceed (); } } NFP111 — Systèmes et Applications Réparties 17 de 48 Plan Beans sessions sans état Objectifs de la norme 3.0 Un premier exemple Cycle de vie Beans sessions Beans sessions sans état Beans sessions avec état Beans messages Beans entités La classe doit être annotée avec @Stateless (import javax.ejb.Stateless ;) Ces beans supportent les callback d’évènements : PostConstruct, PreDestroy, mais aussi PostActivate et PrePassivate qui correpondent aux méthodes ejbActivate et ejbPassivate présentes dans les EJB 2.x. La méthode callback PostConstruct intervient après toutes les injections de dépendances effectuées par le conteneur et avant le premier appel d’une méthode métier. La méthode callback PreDestroy est appelée au moment où l’instance du bean est détruite. NFP111 — Systèmes et Applications Réparties Plan Beans sessions sans état (Exemple) (1/2) Objectifs de la norme 3.0 Un premier exemple L’interface distante du Bean : package calc; import javax.ejb.Remote; Cycle de vie Beans sessions Beans sessions sans état @Remote public interface Calc { public double add(double val1, double val2); public double mult(double val1, double val2); } Beans sessions avec état Beans messages La classe du Bean : package calc; Beans entités import javax.ejb.Stateless; @Stateless public class CalcBean implements Calc { public double add(double val1, double val2) { return val1 + val2; } public double mult(double val1, double val2) { return val1 * val2; } } 18 de 48 NFP111 — Systèmes et Applications Réparties Plan Beans sessions sans état (Exemple) (2/2) Objectifs de la norme 3.0 Un premier exemple Cycle de vie Beans sessions Beans sessions sans état Beans sessions avec état Beans messages Beans entités Le client du bean : import import import import javax.naming.Context; javax.naming.InitialContext; calc.*; java.util.*; public class CalcClient{ public static void main(String[] args) throws Exception { Properties props = System.getProperties(); props.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory"); props.put(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces"); props.put(Context.PROVIDER_URL, "jnp://localhost:1099"); Context ctx = new InitialContext(props); Calc calc = (Calc) ctx.lookup("CalcBean/remote"); double somme = 0; somme = calc.add(5.643, 8.2921); System.out.println("Addition de 5.643 + 8.2921 = "+somme); } } 19 de 48 NFP111 — Systèmes et Applications Réparties 20 de 48 Plan Beans sessions avec état Objectifs de la norme 3.0 Un premier exemple Cycle de vie La classe doit être annotée avec @Statefull (import javax.ejb.Statefull ;) Beans sessions Beans sessions sans état Beans sessions avec état Beans messages Beans entités Ces beans supportent les callback d’évènements : PostConstruct, PreDestroy, PostActivate et PrePassivate. Il existe l’annotation @Remove applicable à une méthode métier et qui implique la destruction du bean après son appel. NFP111 — Systèmes et Applications Réparties Plan Beans sessions avec état (Exemple) (1/3) Objectifs de la norme 3.0 Un premier exemple L’interface distante du Bean : Cycle de vie package panier; Beans sessions Beans sessions sans état import javax.ejb.Remote; import java.util.*; Beans sessions avec état Beans messages Beans entités @Remote public interface Panier{ public void ajouterArticle(int idArticle); public void supprimerArticle(int idArticle); public Vector listerArticles(); public void setNom(String nomClient); public String getNom(); public void remove(); } 21 de 48 NFP111 — Systèmes et Applications Réparties Plan Beans sessions avec état (Exemple) (2/3) Objectifs de la norme 3.0 Un premier exemple Cycle de vie La classe du Bean : package panier; import import import import javax.ejb.Stateful; javax.annotation.PostConstruct; javax.ejb.Remove; java.util.*; @Stateful public class PanierBean implements Panier{ Vector articles; String nomClient; Beans sessions @PostConstruct public void initialise() { articles = new Vector(); nomClient = ""; } Beans sessions sans état Beans sessions avec état public void ajouterArticle(int idArticle) { System.out.println ("Ajout d’un nouvel article"); articles.add(new Integer(idArticle)); } Beans messages Beans entités public void supprimerArticle(int idArticle){ System.out.println ("Suppression d’un article"); articles.remove(new Integer(idArticle)); } public Vector listerArticles(){ return articles; } public void setNom(String nomClient) { this.nomClient = nomClient; } public String getNom() { return nomClient; } @Remove public void remove() { articles = null; } } 22 de 48 NFP111 — Systèmes et Applications Réparties 23 de 48 Plan Beans sessions avec état (Exemple) (3/3) Objectifs de la norme 3.0 Un premier exemple Cycle de vie Beans sessions Beans sessions sans état Le client du bean : import import import import javax.naming.*; javax.rmi.PortableRemoteObject; java.util.*; panier.*; public class PanierClient { public static void main(String[] args) throws Exception { Properties props = System.getProperties(); props.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory"); props.put(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces"); props.put(Context.PROVIDER_URL, "jnp://localhost:1099"); Context ctx = new InitialContext(props); Panier monPanier = (Panier) ctx.lookup("PanierBean/remote"); monPanier.ajouterArticle(65); monPanier.ajouterArticle(53); Beans sessions avec état Beans messages Vector mesArticles = monPanier.listerArticles(); System.out.println ("Il y a "+mesArticles.size()+" article(s) dans le panier !"); Enumeration e = mesArticles.elements(); while (e.hasMoreElements()) { System.out.println((Integer)e.nextElement()); } Beans entités monPanier.ajouterArticle(23); monPanier.ajouterArticle(18); monPanier.supprimerArticle(65); mesArticles = monPanier.listerArticles(); System.out.println ("Il y a "+mesArticles.size()+" article(s) dans le panier !"); e = mesArticles.elements(); while (e.hasMoreElements()) { System.out.println((Integer)e.nextElement()); } monPanier.remove (); } } NFP111 — Systèmes et Applications Réparties 24 de 48 Plan Beans messages Objectifs de la norme 3.0 Un premier exemple Cycle de vie Beans sessions Beans sessions sans état Beans sessions avec état Beans messages Beans entités La classe du bean doit être annotée avec @MessageDriven (import javax.ejb.MessageDriven ;). L’interface du bean doit être du type des que le bean va utiliser. Dans la plupart des cas, il s’agira de javac.jms.MessageListener. Ces beans supportent les callback d’évènements : PostConstruct et PreDestroy. Dans le cas d’une utilisation avec JMS, la méthode public void onMessage (Message msg) doit être redéfinit. Il faut également définir les différents paramètres à utiliser pour la connexion à la destination. Pour cela, on utilise les propriétés : destinationType et destination. NFP111 — Systèmes et Applications Réparties 25 de 48 Plan Beans messages : exemple (1/2) Objectifs de la norme 3.0 Un premier exemple Cycle de vie Beans sessions Beans sessions sans état Beans sessions avec état Beans messages Beans entités La classe du Bean : import javax.annotation.Resource; import javax.ejb.*; import javax.jms.*; @MessageDriven(activationConfig = { @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"), @ActivationConfigProperty(propertyName = "destination", propertyValue = "queue/MessageBean") }) public class MessageBean implements MessageListener { @Resource MessageDrivenContext mdc; //Méthode de réception des messages public void onMessage(Message msg) { TextMessage tm; try { if (msg instanceof TextMessage){ tm = (TextMessage) msg; String text = tm.getText(); System.out.println("Message Bean Reçu : " + text); } else { System.out.println ("Message de mauvais type : "+msg.getClass().getName()); } }catch(JMSException e) { e.printStackTrace(); mdc.setRollbackOnly (); }catch(Throwable te) { te.printStackTrace(); } } } NFP111 — Systèmes et Applications Réparties 26 de 48 Plan Beans messages : exemple (1/2) Objectifs de la norme 3.0 Le client : Un premier exemple import javax.naming.*; import javax.jms.*; import java.util.*; Cycle de vie public class Client { public static void main (String[] args) throws Exception { // Initialisation JNDI Properties props = System.getProperties(); props.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory"); props.put(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces"); props.put(Context.PROVIDER_URL, "jnp://localhost:1099"); Beans sessions Beans sessions sans état Beans sessions avec état Beans messages Context ctx = new InitialContext(props); // 1: recherche d’une fabrique de connection via JNDI QueueConnectionFactory factory = (QueueConnectionFactory) ctx.lookup("ConnectionFactory"); // 2: Utilisation de la fabrique de connexions pour créer une connexion JMS QueueConnection connection = factory.createQueueConnection(); // 3: Utilisation de la connection pour créer une session QueueSession session = connection.createQueueSession(false, QueueSession.AUTO_ACKNOWLEDGE); // 4: Recherche du sujet (topic) via JNDI javax.jms.Queue queue = (javax.jms.Queue) ctx.lookup("queue/MessageBean"); // 5: Création d’un producteur de message QueueSender sender = session.createSender(queue); // 6: Creation d’un message texte et publication TextMessage msg = session.createTextMessage(); for (int i=0;i<10;i++){ msg.setText("Envoi du message : " + i); sender.send(msg); } Beans entités } } NFP111 — Systèmes et Applications Réparties 27 de 48 Plan Beans entités (1/5) Objectifs de la norme 3.0 Un premier exemple Cycle de vie Beans sessions Beans sessions sans état Beans sessions avec état Beans messages Beans entités Ce sont eux aussi des POJOs mais leurs spécifications ont été définies à part car ils ont subi beaucoup de modifications dans la norme 3.0. L’annotation @Entity (import javax.persistance.Entity ;) définit le bean comme étant de type entité. Le bean doit posséder au moins un constructeur par défaut et devra hériter de l’interface Serializable afin d’être utilisable à travers le réseau pour la gestion de la persistance. On peut spécifier deux méthodes différentes pour la gestion de la persistance au moyen de l’option access : @Entity(access=AccessType.FIELD) permet d’accéder directement aux champs à rendre persistant. @Entity(access=AccessType.PROPERTY) oblige le fournisseur à utiliser les accesseurs. NFP111 — Systèmes et Applications Réparties 28 de 48 Plan Beans entités (2/5) Objectifs de la norme 3.0 Un premier exemple Cycle de vie La clé primaire peut-être simple ou composée et doit être déclarée avec l’annotation @Id. Par exemple, pour obtenir une clé qui s’incrémente automatiquement : @Id(generate=GenerateType.AUTO). Pour les clés composées, il faut respecter certains principes : Beans sessions Beans sessions sans état Beans sessions avec état Beans messages Beans entités La classe de la clé primaire doit être public et posséder un constructeur sans arguments. Si l’accès est de type PROPERTY, la classe peut-être soit de type public soit de type protected. La classe doit être sérialisable (implémenter Serializable). Implémentation des méthodes equals() et hashCode(). Si la clé primaire est mappée à de multiples champs ou propriétés, les noms des champs de cette clé doivent être les mêmes ceux utilisés dans le bean entité. Les annotations permettent d’effectuer le mapping objet/relationnel et la gestion des relations entre les entités. NFP111 — Systèmes et Applications Réparties 29 de 48 Plan Beans entités (3/5) Objectifs de la norme 3.0 Un premier exemple Cycle de vie Beans sessions Beans sessions sans état Beans sessions avec état Beans messages Beans entités Lors de la création d’un bean entité, il faut effectuer le mapping de tous ses champs. Un mapping par défaut intervient lorsqu’aucune annotation précède le champ : @Basic spécifie ce comportement. @Table définit la table correspondant à la classe, elle prend en argumant le nom de la table. @Entity(access=accessType.FIELD) @Table(name="PAYS") public class Pays implements Serializable { @Id(generate=GeneratorType.AUTO) private int id; @Basic private String nom; public Pays() { } public Pays(String nom) { this.nom = nom; } public int getId() { return id; } } NFP111 — Systèmes et Applications Réparties 30 de 48 Plan Beans entités (4/5) Objectifs de la norme 3.0 Un premier exemple Cycle de vie Beans sessions Beans sessions sans état Beans sessions avec état Beans messages Beans entités On peut faire correspondre une valeur à un champ spécifique de la base de données en utilisant l’annotation @Column et des options comme name qui spécifie le nom de la colonne, ou des options pour définir si champ peut être nul, ... @Column(name="DESC", nullable=false) public String getDescription() { return description; } Il existe les relations OneToOne, OneToMany, ManyToOne, ManyToMany (définies par les annotations correspondantes). Dans ces cas, il ne faut pas oublier de spécifier les colonnes faisant les jointures. @ManyToOne(optional=false) @JointColumn(name = "CLIENT_ID", nullable = false, updatable = false) public Client getClient (){ return client; } NFP111 — Systèmes et Applications Réparties 31 de 48 Plan Beans entités (5/5) Objectifs de la norme 3.0 Un premier exemple Cycle de vie Beans sessions Beans sessions sans état Beans sessions avec état Beans messages Les beans entités se manipulent par l’intermédiaire d’un EntityManager. Cet EntityManager peut être obtenu à partir d’un Bean Session par injection de dépendance. @Stateless public class EmployeeManager{ @Resource EntityManager em; Beans entités public void void updateEmployeeAddress (int employeeId, Address address) { //Recherche d’un bean Employee emp = (Employee)em.find ("Employee", employeId); emp.setAddress (address); } } NFP111 — Systèmes et Applications Réparties 32 de 48 Plan Beans entités : exemple (1/12) Objectifs de la norme 3.0 Principe de base : Un premier exemple Cycle de vie Beans sessions Beans sessions sans état Beans sessions avec état Beans messages Beans entités On crée un bean entité qui permettra de manipuler des objets persistants. Dans le bean entité, on met en place un mapping entre les attributs du bean et une table de la base de données. Le client n’accède pas directement aux beans entités mais passe par des beans sessions qui effectueront les manipulations nécessaires sur les beans entités. Les beans de l’exemple : ArticleBean : il s’agit du bean entité. ArticleAccessBean : il s’agit d’un bean session sans état. Il est composé de la classe ArticleAccessBean.java et de l’interface ArticleAccess.java. NFP111 — Systèmes et Applications Réparties 33 de 48 Plan Beans entités : exemple (2/12) Objectifs de la norme 3.0 Un premier exemple Cycle de vie L’interface ArticleAccess.java : définition des méthodes métiers. Beans sessions Beans sessions sans état Beans sessions avec état Beans messages Beans entités package article; import javax.ejb.Remote; import java.util.*; @Remote public interface ArticleAccess { public int addArticle (String libelle, double prixUnitaire, String categorie); public void delArticle (int idArticle); public InfosArticle rechercherArticle (int idArticle); public List rechercherLesArticlesParCategorie (String categorie); public List rechercherTousLesArticles (); } NFP111 — Systèmes et Applications Réparties Plan Beans entités : exemple (3/12) Objectifs de la norme 3.0 La classe ArticleAccessBean.java : la méthode Un premier exemple Cycle de vie Beans sessions Beans sessions sans état addArticle package article; import javax.ejb.*; import javax.persistence.*; import java.util.*; Beans sessions avec état @Stateless public class ArticleAccessBean implements ArticleAccess { Beans messages @PersistenceContext(unitName="Articles") EntityManager em; Beans entités public int addArticle (String libelle, double prixUnitaire, String categorie){ ArticleBean ab = new ArticleBean (); ab.setCategorie (categorie); ab.setLibelle (libelle); ab.setPrixUnitaire (prixUnitaire); em.persist(ab); em.flush(); System.out.println ("AccessBean : Ajout de l’article "+ab.getIdArticle ()); return ab.getIdArticle (); } 34 de 48 NFP111 — Systèmes et Applications Réparties 35 de 48 Plan Beans entités : exemple (4/12) Objectifs de la norme 3.0 Un premier exemple La classe ArticleAccessBean.java : la méthode Cycle de vie delArticle Beans sessions Beans sessions sans état Beans sessions avec état Beans messages public void delArticle (int idArticle){ Query query = em.createQuery("DELETE FROM ArticleBean AS a WHERE a.idArticle="+idArticle } public InfosArticle rechercherArticle (int idArticle){ Query query = em.createQuery("SELECT a FROM ArticleBean AS a WHERE a.idArticle="+idArticle); List<ArticleBean> allArticles = query.getResultList(); Beans entités ArticleBean article = allArticles.get(0); return new InfosArticle (article.getIdArticle(), article.getLibelle(), article.getPrixUnitaire(), article.getCategorie()); } NFP111 — Systèmes et Applications Réparties 36 de 48 Plan Beans entités : exemple (5/12) Objectifs de la norme 3.0 Un premier exemple Cycle de vie Beans sessions Beans sessions sans état Beans sessions avec état Beans messages Beans entités La classe ArticleAccessBean.java : la méthode rechercherTousLesArticles public List rechercherTousLesArticles (){ Query query = em.createQuery("SELECT a FROM ArticleBean AS a"); List<ArticleBean> articlesbean = query.getResultList(); Vector<InfosArticle> articles = new Vector(); Iterator i = articlesbean.iterator(); ArticleBean article; while (i.hasNext()) { article = (ArticleBean) i.next(); InfosArticle infos = new InfosArticle (article.getIdArticle(), article.getLibelle(), article.getPrixUnitaire(), article.getCategor articles.add(infos); } return articles; } NFP111 — Systèmes et Applications Réparties 37 de 48 Plan Beans entités : exemple (6/12) Objectifs de la norme 3.0 Un premier exemple La classe ArticleAccessBean.java : la méthode Cycle de vie rechercherLesArticlesParCategorie Beans sessions public List rechercherLesArticlesParCategorie (String categorie){ Query query = em.createQuery("SELECT a FROM ArticleBean AS a WHERE categorie=’"+categori List<ArticleBean> articlesbean = query.getResultList(); Vector<InfosArticle> articles = new Vector(); Iterator i = articlesbean.iterator(); ArticleBean article; while (i.hasNext()) { article = (ArticleBean) i.next(); articles.add(new InfosArticle (article.getIdArticle(), article.getLibelle(), article.getPrixUnitaire(), article.getCategorie())); } return articles; } Beans sessions sans état Beans sessions avec état Beans messages Beans entités } NFP111 — Systèmes et Applications Réparties 38 de 48 Plan Beans entités : exemple (7/12) Objectifs de la norme 3.0 Un premier exemple Cycle de vie Beans sessions Beans sessions sans état Beans sessions avec état Beans messages Beans entités Le fichier de gestion de la persistance : persistence.xml <persistence 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_1_0.xsd" version="1.0"> <persistence-unit name="Articles"> <jta-data-source>java:/DefaultDS</jta-data-source> <properties> <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/> <property name="hibernate.hbm2ddl.auto" value="create-drop"/> </properties> </persistence-unit> </persistence> NFP111 — Systèmes et Applications Réparties 39 de 48 Plan Beans entités : exemple (8/12) Objectifs de la norme 3.0 Le client ArticleClient.java : la méthode creerArticle Un premier exemple Cycle de vie Beans sessions import import import import import javax.naming.*; javax.rmi.*; javax.ejb.*; java.util.*; article.*; public class ArticleClient { Beans sessions sans état Beans sessions avec état Beans messages public void creerArticle(String libelle, double montantUnitaire, String categorie) { ArticleAccess ah; Properties props = System.getProperties(); props.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory"); props.put(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces"); props.put(Context.PROVIDER_URL, "jnp://localhost:1099"); Beans entités try { Context ctx = new InitialContext(props); ah = (ArticleAccess) ctx.lookup("ArticleAccessBean/remote"); System.out.println ("Ajout d’un article : "+ah); int id = ah.addArticle(libelle, montantUnitaire, categorie); System.out.println ("Affichage de l’article "+id); afficherArticle(id); } catch (Throwable th) { System.out.println("Erreur dans creerArticle : " + th); } } NFP111 — Systèmes et Applications Réparties 40 de 48 Plan Beans entités : exemple (9/12) Objectifs de la norme 3.0 Un premier exemple Le client ArticleClient.java : la méthode afficherArticle Cycle de vie Beans sessions Beans sessions sans état Beans sessions avec état Beans messages Beans entités public void afficherArticle(int numeroArticle) { ArticleAccess ah; Properties props = new Properties(); props.put("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory"); props.put("java.naming.factory.url.pkgs", "org.jboss.naming:org.jnp.interfaces"); props.put("java.naming.provider.url", "localhost:1099"); try { Context ic = new InitialContext(props); ah = (ArticleAccess) ic.lookup("ArticleAccessBean/remote"); InfosArticle infos = ah.rechercherArticle(numeroArticle); System.out.println("voici les infos sur l’article : " + infos.idArticle); System.out.println(" id : " + infos.idArticle); System.out.println(" libelle : " + infos.libelle); System.out.println(" prix unitaire : " + infos.prixUnitaire); System.out.println(" categorie : " + infos.categorie); } catch (Throwable th) { System.out.println("GereCommande.creerArticle : " + th); } } NFP111 — Systèmes et Applications Réparties 41 de 48 Plan Beans entités : exemple (10/12) Objectifs de la norme 3.0 Le client ArticleClient.java : la méthode Un premier exemple Cycle de vie afficherArticlesParCategorie public void afficherArticlesParCategorie(String categorie) { ArticleAccess ah; Properties props = new Properties(); props.put("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory"); props.put("java.naming.factory.url.pkgs", "org.jboss.naming:org.jnp.interfaces"); props.put("java.naming.provider.url", "localhost:1099"); try { Context ic = new InitialContext(props); ah = (ArticleAccess) ic.lookup("ArticleAccessBean/remote"); List<InfosArticle> articles = ah.rechercherLesArticlesParCategorie(categorie); Iterator i = articles.iterator(); InfosArticle article; while (i.hasNext()) { article = (InfosArticle) i.next(); afficherArticle(article.idArticle); } } catch (Throwable th) { System.out.println("Erreur dans rechercherArticlesParCategorie : " + th); } Beans sessions Beans sessions sans état Beans sessions avec état Beans messages Beans entités } NFP111 — Systèmes et Applications Réparties 42 de 48 Plan Beans entités : exemple (11/12) Objectifs de la norme 3.0 Le client ArticleClient.java : la méthode Un premier exemple Cycle de vie afficherTousLesArticles public void afficherTousLesArticles() { ArticleAccess ah; Properties props = new Properties(); props.put("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory"); props.put("java.naming.factory.url.pkgs", "org.jboss.naming:org.jnp.interfaces"); props.put("java.naming.provider.url", "localhost:1099"); try { Context ic = new InitialContext(props); ah = (ArticleAccess) ic.lookup("ArticleAccessBean/remote"); List<InfosArticle> articles = ah.rechercherTousLesArticles(); Iterator i = articles.iterator(); InfosArticle article; while (i.hasNext()) { article = (InfosArticle) i.next(); afficherArticle(article.idArticle); } } catch (Throwable th) { System.out.println("Erreur dans rechercherArticlesParCategorie : " + th); } Beans sessions Beans sessions sans état Beans sessions avec état Beans messages Beans entités } NFP111 — Systèmes et Applications Réparties Plan Beans entités : exemple (12/12) Objectifs de la norme 3.0 Le client ArticleClient.java : la méthode main Un premier exemple public static void main(java.lang.String[] args) { Cycle de vie ArticleClient a = new ArticleClient (); a.creerArticle("Les miserables", 21, "LIVRE"); a.creerArticle("Celine Dion au stade de France", 120, "CD"); a.creerArticle("Je l’aime a mourir", 28, "LIVRE"); a.creerArticle("La mer", 38, "LIVRE"); Beans sessions Beans sessions sans état Beans sessions avec état // Recherche de l’article 3 System.out.println ("================================"); a.afficherArticle(3); System.out.println ("================================"); a.afficherTousLesArticles(); System.out.println ("================================"); Beans messages Beans entités // Recherche de la categorie a.afficherArticlesParCategorie("CD"); System.out.println ("================================"); } } 43 de 48 NFP111 — Systèmes et Applications Réparties 44 de 48 Plan Connexion avec une base de données MySQL (1/2) Objectifs de la norme 3.0 Un premier exemple Créer une base de données (Exemple : JBossDB) Cycle de vie Créer un fichier mysql-ds.xml (Le nom importe peu !) Beans sessions Copier ce fichier dans le répertoire de déploiement /usr/local/jboss/server/default/deploy ou encore c :\jboss\server\default\deploy. Beans sessions sans état Beans sessions avec état Beans messages Beans entités Télécharger le connecteur JDBC pour MySQL (fichier JAR) et copier dans le répertoire /usr/local/jboss/server/default/lib ou encore c :\jboss\server\default\deploy. NFP111 — Systèmes et Applications Réparties 45 de 48 Plan Connexion avec une base de données MySQL (2/2) Objectifs de la norme 3.0 Un premier exemple Cycle de vie Beans sessions Beans sessions sans état Beans sessions avec état Beans messages Beans entités Le fichier mysql-ds.xml <?xml version="1.0" encoding="UTF-8"?> <datasources> <local-tx-datasource> <jndi-name>MySQLDS</jndi-name> <connection-url>jdbc:mysql://localhost:3306/JBossDB</connection-url> <driver-class>com.mysql.jdbc.Driver</driver-class> <user-name>duvallet</user-name> <password>duvallet</password> <exception-sorter-class-name> org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter </exception-sorter-class-name> <!-- corresponding type-mapping in the standardjbosscmp-jdbc.xml (optional) --> <metadata> <type-mapping>mySQL</type-mapping> </metadata> </local-tx-datasource> </datasources> NFP111 — Systèmes et Applications Réparties 46 de 48 Plan Les relations Un à Un (One To One) Objectifs de la norme 3.0 Un premier exemple Cycle de vie Beans sessions Beans sessions sans état Beans sessions avec état Beans messages Beans entités Une relation « One To One » est utilisée pour lier deux entités uniques indissociables. Ce type de relation peux-être mappé de trois manières dans la base de données : en utilisant les mêmes valeurs pour les clés primaires des deux entités via l’annotation @PrimaryKeyJoinColumn. en utilisant une clé étrangère d’un coté de la relation via l’annotation @JoinColumn (name="identifiant", referencedColumnName="clé primaire dans l’autre table"). en utilisant une table d’association de liens entre les deux entités via l’annotation @JoinTable(name = "NomDeLaTableDeJointure", joinColumns = @JoinColumn (name="1ère clé étrangère", unique=true), inverseJoinColumns = @JoinColumns(name="2ième clé étrangère", unique=true) NFP111 — Systèmes et Applications Réparties 47 de 48 Plan Les relations Un à Plusieurs (One To Many) et Plusieurs à Objectifs de la norme 3.0 Un (Many To One) Un premier exemple Cycle de vie Beans sessions Beans sessions sans état Beans sessions avec état Beans messages Beans entités Ces deux relations sont utilisées pour lier à une unique instance d’une entité A, un groupe d’instances d’une entité B. L’association « Many To One » est définie par l’annotation @ManyToOne Dans le cas d’une relation bidirectionnelle, l’autre coté doit utiliser l’annotation @OneToMany. Les attributs de ces deux annotations correspondent à ceux de l’annotation @OneToOne. NFP111 — Systèmes et Applications Réparties 48 de 48 Plan Les relations Plusieurs à Plusieurs (Many To Many) Objectifs de la norme 3.0 Un premier exemple Cycle de vie Beans sessions Ces relations sont utilisées pour lier des instances de deux entités entre elles. Beans sessions sans état Beans sessions avec état Beans messages Beans entités Exemple : un article appartient à éventuellement plusieurs catégories et une catégorie contient plusieurs articles. Il est nécessaire d’utiliser une table d’association pour mettre en œuvre cette association.