Vous êtes sur la page 1sur 10

Une introduction ` a la technologie EJB (1/2)

1 Introduction

La technologie des EJB (pour Enterprise Java Bean) ont et e introduite en 1998 pour orir aux programmeurs un outil qui facilite la conception et le d eploiement dune couche m etier. La version 1.0 tr` es simple est largement revue en 2002 avec la version 2.0. Cette derni` ere introduit de nombreuses nouveaut es avec la possibilit e de travailler directement (via des EJB particuliers) sur des donn ees stock ees dans une base de donn ees relationnelle. Malheureusement, ces nouvelles fonctions saccompagnent dune lourdeur tr` es importante de mise en oeuvre. Les composants EJB 2.0 doivent impl ementer de multiples interfaces et leur d eploiement impose de fournir au serveur dapplications des chiers de description fastidieux r edig es en XML. En 2006, la version EJB 3.0 a pour objectif de simplier lutilisation et le d eploiement de cette technologie en se basant sur quatre principes : Les chiers XML de d eploiement sont remplac es par des annotations plac ees directement dans le code des EJB. Cette nouvelle possibilit e est directement li ee aux apports de la version 1.5 de JavaSE (d enition et exploitation des annotations). Pour assurer les interactions entre les EJB et le serveur dapplication dans lequel ils sont install es, le programmeur nest plus oblig e dimpl ementer de nombreuses interfaces (au sens java du terme). Ici encore, les annotations vont simplier les choses. Tous les param` etres de d eploiement sont dot es de valeurs par d efaut qui sussent dans la plupart des cas. Les mouvements de donn ees vers ou ` a partir dune base de donn ees relationnelle vont etre r ealis es par le biais de POJO (Plain Old Java Object ). Ces composants tr` es simples vont remplacer les EJB Entit es de la version 2.0 et ainsi simplier le travail du programmeur. Il faut noter que l` a egalement, les annotations appliqu ees aux POJO vont permettre une mise en oeuvre plus simple. Il existe trois types dEJB : Les EJB Session fournissent un service aux clients. Ils sont accessibles via le r eseau (en passant par le protocole RMI) ou localement dans la JVM du client. Les EJB sessions sont les points dentr ee de la couche m etier. Les EJB Entity repr esentent les donn ees qui proviennent ou qui alimentent la base de donn ees. Ils ne sont g en eralement pas accessibles directement au client. Ce dernier doit, traditionnellement, passer par un EJB session pour r ecup erer des EJB entit es. Les EJB MessageDriven repr esentent une le de messages post es par le client et trait es par le serveur (ou vice-versa). Nous ne les etudierons pas dans ce TP. Quelques liens :

Javadoc de lAPI EJB 3.0 http://docs.oracle.com/javaee/6/api/index.html ?javax/ejb/package-sum Le tutorial JEE sur les EJB http://docs.oracle.com/javaee/6/tutorial/doc/bnblr.html

Mise en place

Pour travailler avec les EJB en version 3.0, nous avons besoin de mettre en place des outils suppl ementaires :

IDE Eclipse JEE (` a sauter si d ej` a fait) Commencez par charger la version JEE de lIDE Eclipse1 . Nous avons besoin de cette version pour utiliser les nombreux plugins quelle int` egre. Serveur dapplications JBoss Continuez en r ecup erant le serveur dapplications JBoss5.x.x2 (aussi disponible ici3 ) qui est indispensable pour d eployer les EJB. Noubliez pas de d ecompresser larchive r ecup er ee. Suivez ensuite ces etapes : Modiez le chier eclipse.ini en lui ajoutant la ligne  -XX:MaxPermSize=512m . Dans Eclipse, assurez-vous que la vue  Servers  est active. Ajoutez un serveur de type  Jboss 5.x  (en utilisant un JRE 1.6) Cr eez un projet de type EJB. En cliquant sur le serveur, ajoutez lui votre nouveau projet.

Les EJB Session

La r ealisation dun EJB Session requi` ere deux etapes. Dans un premier temps, nous devons r ediger le cahier des charges sous la forme dune interface, et dans un deuxi` eme temps, nous devons fournir une implantation. Nous retrouvons donc les concepts d ej` a pr esent es dans la technologie RMI. Il existe deux types dEJB Session : Stateless Session Bean Comme leur nom lindique, ces EJB Session nont pas d etat. En dautres termes, il existe sur le serveur dapplications une ou plusieurs instances de ces EJB qui sont utilis ees par tous les clients de mani` ere simultan ee. En dautres termes, il nexiste pas de liens entre les instances c ot e serveur et les clients. Ces EJB sont souvent utilis es comme guichet unique dune couche m etier. Stateful Session Bean Contrairement aux Stateless, les Stateful poss` edent un etat qui re` ete l etat de la discussion avec un client particulier. En dautres termes, il existe dans le S.A. autant dinstances que de clients connect es au serveur. Les instances dun EJB Session Stateful sont donc sp eciques ` a un client. Ces EJB sont souvent utilis es pour repr esenter un utilisateur connect e.

3.1

Un Stateless Session Bean

Nous allons commencer par construire un petit EJB Session Stateless dont le but est de passer une cha ne de caract` eres en majuscule. Nous commencons par d enir linterface :
package monpkg.services; import javax.ejb.Remote; @Remote public interface ToUpper { String toUpper(String data); }

Dans cette interface, lannotation javax.ejb.Remote4 est utilis ee pour pr eciser que lEJB sera accessible via le protocole RMI. Si lEJB est implant e dans la m eme JVM, nous aurions du utiliser lannotation javax.ejb.Local5 . Un EJB peut etre ` a la fois distant et local. Il faut dans ce cas deux interfaces. puis nous r ealisons une implantation :
1 2

http://www.eclipse.org/downloads/ http://labs.jboss.com/jbossas/ 3 ref:ress-ejb 4 http ://docs.oracle.com/javaee/6/api/ ?javax/ejb/Remote.html 5 http ://docs.oracle.com/javaee/6/api/ ?javax/ejb/Local.html

package monpkg.impl; import javax.ejb.Stateless; import monpkg.services.ToUpper; @Stateless(name = "toUpper", description = "Un premier essai") public class ToUpperImpl implements ToUpper { public String toUpper(String qui) { return qui.toUpperCase(); } }

Lannotation javax.ejb.Stateless6 permet de typer votre EJB et de lui donner un nom. A ce stade vous pouvez demander un synchronisation de votre serveur (op eration qui d eploie le JAR de votre projet dans le serveur dapplications). V eriez quil ny a pas derreur. Consultez la console JMX de JBoss (http://localhost:8080/jmx-console) et v eriez que votre application est bien pr esente.

3.2

Mise en place du client

Nous allons maintenant cr eer le client sous la forme dun nouveau projet. Mettez en place une d ependance entre le projet client et le projet EJB et copiez dans votre projet client la librairie client/jbossall-client.jar qui se trouve dans le r epertoire de JBoss.
package monclient; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; import monpkg.services.ToUpper; import static org.junit.Assert.*; import org.junit.Before; import org.junit.Test; public class TestMonEJB { final Context initial; public TestMonEJB() throws NamingException { initial = new InitialContext(); } @Test public void testToUpper() throws NamingException { Object o = initial.lookup("toUpper/remote"); assertTrue(o instanceof ToUpper); ToUpper p = (ToUpper) o; assertEquals("PREMIER", p.toUpper("premier")); } }
6

http ://docs.oracle.com/javaee/6/api/ ?javax/ejb/Stateless.html

Pour eviter de pr eciser dans le code les param` etres de connexion JNDI, vous pouvez cr eer un chier de ressources  jndi.properties  accessible via le CLASSPATH :
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces java.naming.provider.url=localhost:1099

Le nom que nous utilisons pour rep erer un EJB est de la forme nom/remote si lEJB est accessible via RMI ou nom/local si lEJB est disponible dans la m eme JVM. Si vos EJB sont packag es dans une application dentreprise (une EAR : Enterprise Application aRchive ), alors le chemin devient nom-de-EAR/nom-de-EJB/remote ou nom-de-EAR/nom-de-EJB/local. Une archive EAR regroupe des EJB (packag es dans un .jar) et une application WEB (packag e dans un .war). Vous pouvez, dans Eclipse, cr eer une application dentreprise pour regrouper un ensemble dEJB et une application WEB. Testez votre application.

3.3

Cycle de vie dun EJB

Un EJB a souvent besoin d etre inform e (par le serveur dapplications) de sa cr eation et de sa destruction. Dans les EJB2, de nombreuses interfaces etaient pr evues pour assurer cette fonction. Dans les EJB3, il sut dannoter certaines m ethodes pour quelles soient appel ees par le S.A.
@PostConstruct() public void debut() { System.out.println("Starting " + this); } @PreDestroy public void fin() { System.out.println("Stopping " + this); }

Ajoutez ces callbacks ` a votre EJB et testez leur fonctionnement. Vous pouvez remarquer que ces annotations7 ne sont pas directement li ees ` a la technologie des EJB3.

3.4

Un EJB Session Stateful

Essayons maintenant de construire un Stateful Session Bean. Nous allons utiliser le cas classique dun utilisateur connect e. Commencons par d enir linterface :
package monpkg.services; import javax.ejb.Remote; @Remote public interface ConnectedUser { void login(String login, String pwd); void logout(); }

Puis limplantation :
7

http://docs.oracle.com/javaee/6/api/javax/annotation/package-summary.html

package monpkg.impl; import javax.annotation.PostConstruct; @Stateful(name="connectedUser") public class ConnectedUserBean implements ConnectedUser { // implantation des m ethodes ... }

Lannotation javax.ejb.Stateful8 indique au serveur dapplication quil doit cr eer une instance de cet EJB pour chaque client. V eriez que cest bien le cas avec des traces g en er ees par des m ethodes annot ees par @PostConstruct. Normalement le client doit etre capable de terminer un EJB Stateful. Pour ce faire, vous devez annoter les m ethodes qui terminent ce bean avec @Remove. Le bean sera d etruit apr` es avoir ex ecut e la m ethode.
@Remove public void logout() { System.out.println("Logout user "+this); }

Utilisez ces principes pour authentier et d econnecter un utilisateur. V eriez les cycles de vie du Stateful Session Bean avec une m ethode annot ee par @PreDestroy. Essayez dutiliser une instance apr` es lavoir d etruite.

Injection dEJB

Nous avons souvent besoin, dans une application, dutiliser un premier EJB dans limplantation dun second. Pour ce faire, nous devons faire un lien entre ces deux EJB. Nous pouvons toujours le faire en consid erant lEJB utilisateur comme un client et donc passer par un lookup JNDI. Pour simplier ces probl` emes de liaison, la norme EJB3 introduit la notion dinjection de d ependances via lannotation javax.ejb.EJB9 :
@EJB private ToUpper toUpper;

En ajoutant ce code au bean ConnectedUserBean nous sommes capable dutiliser directement lEJB toUpper dans limplantation. Les injections sont r ealis ees apr` es la cr eation et avant lappel des callbacks @PostConstruct. Pour mettre en oeuvre ce principe, cr eez un Stateless Session Bean qui ore un service de log et injectez cet EJB dans votre utilisateur connect e pour suivre les cr eations, authentications et destructions.

Les intercepteurs

Il est souvent utile de pouvoir surveiller lex ecution dune m ethode en eectuant un traitement avant et apr` es lex ecution. Cest lune des bases de la programmation orient ee Aspect10 . Nous retrouvons cette possibilit e dans la norme EJB3 en d enissant des m ethodes particuli` eres qui vont intercepter les appels aux m ethodes m etier via lannotation javax.interceptor.AroundInvoke11 . Cest loccasion de simplier les m ethodes m etiers en d elocalisant le code technique (trace, v erication, sauvegarde) dans des classes de surveillance.
http ://docs.oracle.com/javaee/6/api/ ?javax/ejb/Stateful.html http ://docs.oracle.com/javaee/6/api/ ?javax/ejb/EJB.html 10 http://fr.wikipedia.org/wiki/Programmation orient%C3%A9e aspect 11 http ://docs.oracle.com/javaee/6/api/ ?javax/interceptor/AroundInvoke.html
9 8

import javax.interceptor.AroundInvoke; import javax.interceptor.InvocationContext; ... @AroundInvoke public Object interceptor(InvocationContext context) throws Exception { String methodName = context.getMethod().getName(); System.err.println("appel de " + methodName); for (Object param : context.getParameters()) { System.err.println("param = " + param.toString()); } return context.proceed(); }

Ces m ethodes sont plac ees dans la classe ` a surveiller ou dans une classe annexe (ou les deux). Dans le cas dune classe dinterception, vous devez donner son nom avec lannotation javax.interceptor.Interceptors12 (il peut y en avoir plusieurs) :
package monpkg.impl; import javax.interceptor.AroundInvoke; import javax.interceptor.InvocationContext; public class Interceptor { @AroundInvoke public Object interceptor(InvocationContext context) throws Exception { ... } }

Classe m etier ` a surveiller :


package monpkg.impl; import javax.interceptor.Interceptors; @Interceptors({Interceptor.class}) public class LaClasseASurveiller implements MonService { ... }

Pour nir, une m ethode pour d econnecter la surveillance eectu ee par une autre classe en utilisant lannotation @ExcludeClassInterceptors. Mise en oeuvre : Cr eez un intercepteur qui va calculer la temps pris par les appels aux m ethodes m etiers (utilisez System.currentTimeMillis()).

Petits exercices

Je vous propose de suivre un petit exercice :


12

http ://docs.oracle.com/javaee/6/api/ ?javax/interceptor/Interceptors.html

Utilisation des Timers http://java.sun.com/javaee/5/docs/tutorial/doc/bnboy.html Cet exemple illustre le m ecanisme des timers et linjection de ressources.

JPA et EJB

Pour la mise en pratique de JPA, nous allons utiliser lenvironnement EJB 3 bas e sur JBoss que nous avons mis en place lors du TP pr ec edent. Nous allons lui ajouter quelques el ements :

7.1

Param etrage JPA

Le chier META-INF/persistence.xml (dans le r epertoire source) :


<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="myPersistenceUnit" transaction-type="JTA"> <jta-data-source>java:/DefaultDS</jta-data-source> <properties> <property name="hibernate.show_sql" value="true" /> <property name="hibernate.format_sql" value="false" /> <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect" /> <property name="hibernate.hbm2ddl.auto" value="create-drop" /> </properties> </persistence-unit> </persistence>

On trouve dans ce chier la description et les param` etres du fournisseur de persistance. Dans notre exemple, nous nous basons sur une Datasource qui existe par d efaut dans JBoss. Vous trouverez sa description dans le chier : <JBOSS_DIR>/server/all/deploy/hsqldb-ds.xml (vous pouvez regarder les exemples de DataSource dans le r epertoire <JBOSS_DIR>/docs/examples/jca/).

7.2

Le service DAO

Commen cons par d enir un service DAO classique :


package monpkg.services; import java.util.List; import monpkg.entities.Person; public interface Dao { List<Person> findAllPersons(); Person addPerson(Person p); Person findPerson(long id); }

pour lentit e personne :


package monpkg.entities; import java.io.Serializable; import import import import import javax.persistence.Column; javax.persistence.Entity; javax.persistence.GeneratedValue; javax.persistence.GenerationType; javax.persistence.Id;

@Entity public class Person implements Serializable { private static final long serialVersionUID = 1L; @Id() @GeneratedValue(strategy = GenerationType.AUTO) private long id; @Column(name = "name", length = 200, nullable = false) private String name; public Person() { super(); } public Person(String name) { super(); this.name = name; } @Override public String toString() { return "Person(id=" + id + "," + name + ")"; } public long getId() { return id; } public void setId(long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }

7.3

Un EJB DAO

Nous pouvons maintenant donner une implantation du service DAO :

package monpkg.impl; import java.util.List; import import import import import import javax.annotation.PostConstruct; javax.ejb.Remote; javax.ejb.Stateless; javax.persistence.EntityManager; javax.persistence.PersistenceContext; javax.persistence.Query;

import monpkg.entities.Person; import monpkg.services.Dao; @Remote(value = Dao.class) @Stateless(name = "dao", description = "My Dao EJB") public class DaoImpl implements Dao { @PersistenceContext(unitName = "myPersistenceUnit") EntityManager em; @PostConstruct public void init() { System.err.println("Dao init : " + this); System.err.println("em = " + em); } @Override public Person addPerson(Person p) { em.persist(p); return (p); } @Override public Person findPerson(long id) { return em.find(Person.class, id); } @SuppressWarnings("unchecked") @Override public List<Person> findAllPersons() { Query q = em.createQuery("FROM Person"); return q.getResultList(); } }

Explications : via le m ecanisme dinjection (annotation javax.persistence.PersistenceContext13 ), lEJB r ecup` ere une instance de linterface javax.persistence.EntityManager14 . Celle-ci va permettre les op erations CRUD de persistance sur les entit es (Create, Read, Update et Delete). Cette instance est pr epar ee par le serveur dapplication ` a partir du chier persistence.xml. V erication : Apr` es d eploiement de cet EJB, vous devez trouver dans les traces de JBOSS la conguration de la source de donn ees.

7.4

Test de lEJB DAO

Dans le projet client enrichissez la classe de test pour tester lEJB Dao.
13 14

http ://docs.oracle.com/javaee/6/api/ ?javax/persistence/PersistenceContext.html http ://docs.oracle.com/javaee/6/api/ ?javax/persistence/EntityManager.html

V erication : La base de donn ees embarqu ee Hypersonic que nous utilisons dans cet exemple maintient un chier de trace qui est particuli` erement int eressant. Il liste notamment les ordres de cr eation des tables ainsi que les op erations sur les lignes. Vous pouvez le trouver ` a cet emplacement : <JBOSS_DIR>/server/default/data/hypersonic/localDB.log

EJB Embarqu es

De nombreuses applications veulent utiliser les avantages des EJBs sans avoir ` a d eployer un serveur dapplications. Pour ce faire, on peut utiliser un serveur dapplications embarqu e qui se pr esente sous la forme dune librairie Java : T el echargez OpenEJB15 en version standalone (aussi disponible ici16 ), d ecompressez larchive obtenue, Cr eez un nouveau projet Java dans Eclipse, Ajoutez au buildpath une nouvelle librairie utilisateur (que vous allez cr eer pour loccasion) qui regroupe la totalit e des chiers .jar se trouvant dans le r epertoire lib/ de OpenEJB. Testez ces exemples : http://openejb.apache.org/examples-trunk/simple-stateless/README.html http://openejb.apache.org/examples-trunk/simple-stateful/README.html http://openejb.apache.org/examples-trunk/injection-of-entitymanager/README.html Remarque : Dans ces exemples, vous utilisez la version 3.1 des EJB dans laquelle les interfaces sont devenues optionnelles.

15 16

http://openejb.apache.org/ ref:ress-ejb

10