Vous êtes sur la page 1sur 11

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 uvre. 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 le fichier 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)

Crez un projet de type EJB.

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

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