Vous êtes sur la page 1sur 11

Une introduction la technologie EJB (1/2)

La technologie des EJB (pour Enterprise Java Bean) ont t introduite en 1998 pour
offrir aux programmeurs un outil qui facilite la conception et le dploiement d'une
couche mtier. La version 1.0 trs simple est largement revue en 2002 avec la
version 2.0. Cette dernire introduit de nombreuses nouveauts avec la possibilit
de travailler directement (via des EJB particuliers) sur des donnes stockes dans
une base de donnes relationnelle.
Malheureusement, ces nouvelles fonctions s'accompagnent d'une lourdeur trs
importante de mise en oeuvre. Les composants EJB 2.0 doivent implmenter de
multiples interfaces et leur dploiement impose de fournir au serveur d'applications
des fichiers de description fastidieux rdigs en XML.
En 2006, la version EJB 3.0 a pour objectif de simplifier l'utilisation et le dploiement
de cette technologie en se basant sur quatre principes :

Les fichiers XML de dploiement sont remplacs par des annotations places
directement dans le code des EJB. Cette nouvelle possibilit est directement lie
aux apports de la version 1.5 de JavaSE (dfinition et exploitation des
annotations).

Pour assurer les interactions entre les EJB et le serveur d'application dans lequel
ils sont installs, le programmeur n'est plus oblig d'implmenter de nombreuses
interfaces (au sens java du terme). Ici encore, les annotations vont simplifier les
choses.

Tous les paramtres de dploiement sont dots de valeurs par dfaut qui
suffissent dans la plupart des cas.

Les mouvements de donnes vers ou partir d'une base de donnes


relationnelle vont tre raliss par le biais de POJO (Plain Old Java Object).
Ces composants trs simples vont remplacer les EJB Entits de la
version 2.0 et ainsi simplifier le travail du programmeur. Il faut noter que l
galement, les annotations appliques aux POJO vont permettre une mise en
oeuvre plus simple.

Il existe trois types d'EJB :

Les EJB Session fournissent un service aux clients. Ils sont accessibles via le
rseau (en passant par le protocole RMI) ou localement dans la JVM du client.
Les EJB sessions sont les points d'entre de la couche mtier.

Les EJB Entity reprsentent les donnes qui proviennent ou qui alimentent la
base de donnes. Ils ne sont gnralement pas accessibles directement au

client. Ce dernier doit, traditionnellement, passer par un EJB session pour


rcuprer des EJB entits.

Les EJB MessageDriven reprsentent une file de messages posts par le client
et traits par le serveur (ou vice-versa). Nous ne les tudierons pas dans ce TP.

Mise en place

Pour travailler avec les EJB en version 3.0, nous avons besoin de mettre en place
des outils supplmentaires :
IDE Eclipse JEE
( sauter si dj fait)
Commencez par charger la version JEE de l'IDE Eclipse. Nous avons besoin de
cette version pour utiliser les nombreux plugins qu'elle intgre.
Serveur d'applications JBoss
Continuez en rcuprant le serveur d'applications JBoss 5.x.x qui est
indispensable pour dployer les EJB. N'oubliez pas de dcompresser l'archive
rcupre.

Suivez ensuite ces tapes :

Modifiez

Dans Eclipse, assurez-vous que la vue Servers est active.

Ajoutez un serveur de type Jboss 5.x (en utilisant un JRE 1.6)

Crez un projet de type EJB.

En cliquant sur le serveur, ajoutez lui votre nouveau projet.

le
fichier eclipse.ini en
XX:MaxPermSize=512m .

lui

ajoutant

la

ligne

Un Stateless Session Bean

Nous allons commencer par construire un petit EJB Session Stateless dont le but est
de passer une chane de caractres en majuscule. Nous commencons par dfinir
l'interface :
packagemonpkg.services;
importjavax.ejb.Remote;
@Remote
publicinterfaceToUpper{
StringtoUpper(Stringdata);

Dans cette interface, l'annotation javax.ejb.Remote est utilise pour prciser que
l'EJB sera accessible via le protocole RMI. Si l'EJB est implant dans la mme JVM,
nous aurions du utiliser l'annotation javax.ejb.Local. Un EJB peut tre la fois
distant et local. Il faut dans ce cas deux interfaces.
puis nous ralisons une implantation :
packagemonpkg.impl;
importjavax.ejb.Stateless;
importmonpkg.services.ToUpper;
@Stateless(name="toUpper",description="Unpremieressai")
publicclassToUpperImplimplementsToUpper{
publicStringtoUpper(Stringqui){
returnqui.toUpperCase();
}
}

L'annotation javax.ejb.Stateless permet de typer votre EJB et de lui donner un


nom. A ce stade vous pouvez demander un synchronisation de votre serveur
(opration qui dploie le JAR de votre projet dans le serveur d'applications). Vrifiez
qu'il n'y a pas d'erreur. Consultez la console JMX de JBoss
(http://localhost:8080/jmxconsole) et vrifiez que votre application est bien
prsente.

Mise en place du client

Nous allons maintenant crer le client sous la forme d'un nouveau projet. Mettez en
place une dpendance entre le projet client et le projet EJB et copiez dans votre
projet client la librairie client/jbossallclient.jar qui se trouve dans le
rpertoire de JBoss.
packagemonclient;
importjavax.naming.Context;
importjavax.naming.InitialContext;
importjavax.naming.NamingException;
importmonpkg.services.ToUpper;
importstaticorg.junit.Assert.*;
importorg.junit.Before;
importorg.junit.Test;

publicclassTestMonEJB{
finalContextinitial;
publicTestMonEJB()throwsNamingException{
initial=newInitialContext();
}
@Test
publicvoidtestToUpper()throwsNamingException{
Objecto=initial.lookup("toUpper/remote");
assertTrue(oinstanceofToUpper);
ToUpperp=(ToUpper)o;
assertEquals("PREMIER",p.toUpper("premier"));
}
}

Pour viter de prciser dans le code les paramtres de connexion JNDI, vous
pouvez crer un fichier 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 reprer un EJB est de la forme nom/remote si l'EJB

est accessible via RMI ou nom/local si l'EJB est disponible dans la mme JVM. Si
vos EJB sont packags dans une application d'entreprise (une EAR : Enterprise
Application
aRchive),
alors
le
chemin
devient nomdeEAR/nomde
EJB/remote ou nomdeEAR/nomdeEJB/local. Une archive EAR regroupe des EJB
(packags dans un .jar) et une application WEB (packag dans un .war). Vous
pouvez, dans Eclipse, crer une application d'entreprise pour regrouper un
ensemble d'EJB et une application WEB.
Testez votre application.
Cycle de vie d'un EJB

Un EJB a souvent besoin d'tre inform (par le serveur d'applications) de sa cration


et de sa destruction. Dans les EJB2, de nombreuses interfaces taient prvues pour
assurer cette fonction. Dans les EJB3, il suffit d'annoter certaines mthodes pour
qu'elles soient appeles par le S.A.
@PostConstruct()
publicvoiddebut(){
System.out.println("Starting"+this);
}
@PreDestroy

publicvoidfin(){
System.out.println("Stopping"+this);
}

Ajoutez ces callbacks votre EJB et testez leur fonctionnement. Vous pouvez
remarquer que ces annotations ne sont pas directement lies la technologie des
EJB3.
Un EJB Session Stateful

Essayons maintenant de construire un Stateful Session Bean. Nous allons utiliser


le cas classique d'un utilisateur connect. Commencons par dfinir l'interface :
packagemonpkg.services;
importjavax.ejb.Remote;
@Remote
publicinterfaceConnectedUser{
voidlogin(Stringlogin,Stringpwd);
voidlogout();
}

Puis l'implantation :
packagemonpkg.impl;
importjavax.annotation.PostConstruct;
@Stateful(name="connectedUser")
publicclassConnectedUserBeanimplementsConnectedUser{

//implantationdesmthodes
...
}

L'annotation javax.ejb.Stateful indique au serveur d'application qu'il doit crer


une instance de cet EJB pour chaque client. Vrifiez que c'est bien le cas avec des
traces gnres par des mthodes annotes par @PostConstruct.
Normalement le client doit tre capable de terminer un EJB Stateful. Pour ce faire,
vous devez annoter les mthodes qui terminent ce bean avec @Remove. Le bean sera
dtruit aprs avoir excut la mthode.
@Remove
publicvoidlogout(){
System.out.println("Logoutuser"+this);
}

Utilisez ces principes pour authentifier et dconnecter un utilisateur. Vrifiez les


cycles de vie du Stateful Session Bean avec une mthode annote
par @PreDestroy. Essayez d'utiliser une instance aprs l'avoir dtruite.
Injection d'EJB

Nous avons souvent besoin, dans une application, d'utiliser un premier EJB dans
l'implantation d'un second. Pour ce faire, nous devons faire un lien entre ces deux
EJB. Nous pouvons toujours le faire en considrant l'EJB utilisateur comme un client
et donc passer par un lookup JNDI. Pour simplifier ces problmes de liaison, la
norme
EJB3
introduit
la
notion
d'injection
de
dpendances
via
l'annotation javax.ejb.EJB :
@EJB
privateToUppertoUpper;

En ajoutant ce code au bean ConnectedUserBean nous sommes capable d'utiliser


directement l'EJB toUpper dans l'implantation. Les injections sont ralises aprs la
cration et avant l'appel des callbacks @PostConstruct.
Pour mettre en oeuvre ce principe, crez un Stateless Session Bean qui offre un
service de log et injectez cet EJB dans votre utilisateur connect pour suivre les
crations, authentifications et destructions.
Les intercepteurs

Il est souvent utile de pouvoir surveiller l'excution d'une mthode en effectuant un


traitement avant et aprs l'excution. C'est l'une des bases de la programmation
oriente Aspect. Nous retrouvons cette possibilit dans la norme EJB3 en
dfinissant des mthodes particulires qui vont intercepter les appels aux mthodes
mtier via l'annotationjavax.interceptor.AroundInvoke. C'est l'occasion
de simplifier les mthodes mtiers en dlocalisant le code technique (trace,
vrification, sauvegarde) dans des classes de surveillance.
importjavax.interceptor.AroundInvoke;
importjavax.interceptor.InvocationContext;
...
@AroundInvoke
publicObjectinterceptor(InvocationContextcontext)throwsException{
StringmethodName=context.getMethod().getName();
System.err.println("appelde"+methodName);
for(Objectparam:context.getParameters()){
System.err.println("param="+param.toString());
}
returncontext.proceed();
}

Ces mthodes sont places dans la classe surveiller ou dans une classe annexe
(ou les deux). Dans le cas d'une classe d'interception, vous devez donner son nom
avec l'annotation javax.interceptor.Interceptors (il peut y en avoir plusieurs) :
packagemonpkg.impl;
importjavax.interceptor.AroundInvoke;
importjavax.interceptor.InvocationContext;
publicclassInterceptor{
@AroundInvoke
publicObjectinterceptor(InvocationContextcontext)throwsException
{
...
}
}

Classe mtier surveiller :


packagemonpkg.impl;
importjavax.interceptor.Interceptors;
@Interceptors({Interceptor.class})
publicclassLaClasseASurveillerimplementsMonService{
...
}

Pour finir, une mthode pour dconnecter la surveillance effectue par une autre
classe en utilisant l'annotation @ExcludeClassInterceptors.
Mise en oeuvre : Crez un intercepteur qui va calculer la temps pris par les appels
aux mthodes mtiers (utilisez System.currentTimeMillis()).

JPA et EJB

Pour la mise en pratique de JPA, nous allons utiliser l'environnement EJB 3 bas sur
JBoss que nous avons mis en place lors du TP prcdent. Nous allons lui ajouter
quelques lments :
Paramtrage JPA

Le fichier METAINF/persistence.xml (dans le rpertoire source) :


<persistencexmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchemainstance"

xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
version="1.0">
<persistenceunitname="myPersistenceUnit"
transactiontype="JTA">
<jtadatasource>java:/DefaultDS</jtadatasource>
<properties>
<propertyname="hibernate.show_sql"value="true"/>
<propertyname="hibernate.format_sql"value="false"/>
<propertyname="hibernate.dialect"
value="org.hibernate.dialect.HSQLDialect"/>
<propertyname="hibernate.hbm2ddl.auto"value="createdrop"/>
</properties>
</persistenceunit>
</persistence>

On trouve dans ce fichier la description et les paramtres du fournisseur de


persistance. Dans notre exemple, nous nous basons sur une Datasource qui existe
par dfaut dans JBoss. Vous trouverez sa description dans le
fichier : <JBOSS_DIR>/server/all/deploy/hsqldbds.xml (vous pouvez regarder
les exemples de DataSource dans le rpertoire<JBOSS_DIR>/docs/examples/jca/).
Le service DAO

Commenons par dfinir un service DAO classique :


packagemonpkg.services;
importjava.util.List;
importmonpkg.entities.Person;
publicinterfaceDao{
List<Person>findAllPersons();
PersonaddPerson(Personp);
PersonfindPerson(longid);
}

pour l'entit personne :


packagemonpkg.entities;
importjava.io.Serializable;
importjavax.persistence.Column;
importjavax.persistence.Entity;
importjavax.persistence.GeneratedValue;
importjavax.persistence.GenerationType;
importjavax.persistence.Id;

@Entity
publicclassPersonimplementsSerializable{
privatestaticfinallongserialVersionUID=1L;
@Id()
@GeneratedValue(strategy=GenerationType.AUTO)
privatelongid;
@Column(name="name",length=200,nullable=false)
privateStringname;
publicPerson(){
super();
}
publicPerson(Stringname){
super();
this.name=name;
}
@Override
publicStringtoString(){
return"Person(id="+id+","+name+")";
}
publiclonggetId(){
returnid;
}
publicvoidsetId(longid){
this.id=id;
}
publicStringgetName(){
returnname;
}
publicvoidsetName(Stringname){
this.name=name;
}
}

Un EJB DAO

Nous pouvons maintenant donner une implantation du service DAO :


packagemonpkg.impl;
importjava.util.List;

importjavax.annotation.PostConstruct;
importjavax.ejb.Remote;
importjavax.ejb.Stateless;
importjavax.persistence.EntityManager;
importjavax.persistence.PersistenceContext;
importjavax.persistence.Query;
importmonpkg.entities.Person;
importmonpkg.services.Dao;
@Remote(value=Dao.class)
@Stateless(name="dao",description="MyDaoEJB")
publicclassDaoImplimplementsDao{
@PersistenceContext(unitName="myPersistenceUnit")
EntityManagerem;
@PostConstruct
publicvoidinit(){
System.err.println("Daoinit:"+this);
System.err.println("em="+em);
}
@Override
publicPersonaddPerson(Personp){
em.persist(p);
return(p);
}
@Override
publicPersonfindPerson(longid){
returnem.find(Person.class,id);
}
@SuppressWarnings("unchecked")
@Override
publicList<Person>findAllPersons(){
Queryq=em.createQuery("FROMPerson");
returnq.getResultList();
}
}

Explications :
via
le
mcanisme
d'injection
(annotation javax.persistence.PersistenceContext), l'EJB rcupre une instance
de l'interfacejavax.persistence.EntityManager. Celle-ci va permettre les
oprations CRUD de persistance sur les entits (Create, Read, Update et Delete).
Cette instance est prpare par le serveur d'application partir du
fichier persistence.xml.
Vrification : Aprs dploiement de cet EJB, vous devez trouver dans les traces de
JBOSS la configuration de la source de donnes.

Test de l'EJB DAO

Dans le projet client enrichissez la classe de test pour tester l'EJB Dao.
Vrification : La base de donnes embarque Hypersonic que nous utilisons dans
cet exemple maintient un fichier de trace qui est particulirement intressant. Il liste
notamment les ordres de cration des tables ainsi que les oprations sur les lignes.
Vous pouvez le trouver cet emplacement :
<JBOSS_DIR>/server/default/data/hypersonic/localDB.log

Vous aimerez peut-être aussi