Explorer les Livres électroniques
Catégories
Explorer les Livres audio
Catégories
Explorer les Magazines
Catégories
Explorer les Documents
Catégories
(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.
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 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 :
( 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.
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.
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.
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.
@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.
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.
<JBOSS_DIR>/server/default/data/hypersonic/localDB.log