4. INSA - ASI InfoRep : EJB 4/65
Introduction (2/3)
Histoire
Aspect programmation
Années 70-80 : Programmation procédurale
alors que les premiers langages objets datent de la fin des années 60 !
Années 90 : Programmation objet
Fin des années 90 : Programmation par composants
Les composants peuvent être physiquement distants
Si changement, pas besoin de tout recompiler et de tout relinker
Bonne programmation objet : seules les interfaces sont connues
5. INSA - ASI InfoRep : EJB 5/65
Introduction (3/3)
J2EE
Volonté de SUN
Cadre de développement par composants avec services
J2EE (Java 2 Edition Enterprise), qui propose des API :
L’invocation de méthodes distantes : RMI, CORBA, Web Services
L’accès aux bases de données relationnelles : JDBC
L’accès aux annuaires et services de nommage : JNDI
L’utilisation du XML : DOM et SAX
HTML dynamique et traitement de requêtes HTTP : JSP et Servlet
La gestion du Mail : Java Mail
La gestion des composants : EJB
La gestion des messages entre composants : Java Message Service
La gestion des droits d’accès : Java Authentication and Authorization
Service (JAAS)
6. INSA - ASI InfoRep : EJB 6/65
Architecture J2EE (1/4)
Description de l’architecture J2EE
7. INSA - ASI InfoRep : EJB 7/65
Architecture J2EE (2/4)
Rappels : J2EE et les conteneurs Web
La spécification J2EE fournit les éléments suivants pour la
conception et la réalisation d’application Web :
Servlets Java et JSP
Les servlets et JSP constituent les blocs de construction du
développement d’applications web avec J2EE
En terme J2EE, les servlets et pages JSP sont des composants web
Application web
Collection de servlets et de pages JSP, d’autres classes annexes ou de
bibliothèques de classes, ainsi que des ressources statiques telles que
des documents HTML, XHTML ou XML, images, etc.
Conteneur web
Essentiellement un environnement d’exécution Java pour les
applications web
Responsable de l’initialisation, de l’invocation et de la gestion de la
durée de vie des servlets Java et des pages JSP
8. INSA - ASI InfoRep : EJB 8/65
Architecture J2EE (3/4)
Rappels : J2EE et les conteneurs Web
Éléments de la spécification J2EE (suite) :
structure de paquetage et descripteur de déploiement
le descripteur de déploiement est un fichier XML
Classes Java
Archives
Description de déploiement
Classes Java
Archives
Description de déploiement
Conteneur web
Servlets
Page JSP
Application web
Servlets
Page JSP
Application web
9. INSA - ASI InfoRep : EJB 9/65
Architecture J2EE (4/4)
Rappels : J2EE et les conteneurs Web
Exemple de conteneur Web
Tomcat
http://www.apache.org
10. INSA - ASI InfoRep : EJB 10/65
Les EJB (1/11)
Description
Un composant EJB est constitué d’une collection de
classes/interfaces Java
Les classes Java doivent respecter certaines règles (Spécifications)
Le composant EJB s’exécute dans un conteneur EJB, qui prend en
charge tout ce qui concerne le niveau système
Répartition des tâches entre le programmeur d’EJB et le conteneur
Les composant EJB fonctionnent avec tout type de client :
servlets et JSP
clients Java (via RMI)
clients et serveur divers (via RMI-IIOP, Services Web)
. . .
3 types d’EJB : entité, session, message
11. INSA - ASI InfoRep : EJB 11/65
Les EJB (2/11)
Variétés d’EJB : les EJB entité
Représentation orientée objet de données dans une base de données
Les clients peuvent y accéder en toute sécurité simultanément
La durée de vie de l’EJB est exactement identique à celle des données
qu’il représente
La relation d’un EJB entité avec les données de la base de données
peut être gérée par
le programmeur : persistance gérée par l’EJB
le conteneur : persistance gérée par le conteneur
Cette distinction se révélera souvent essentielle du point de vue des
performances
Cependant on peut utiliser n’importe quel type d’EJB de manière
interchangeable dans la conception
12. INSA - ASI InfoRep : EJB 12/65
Les EJB (3/11)
Variétés d’EJB : les EJB session
Client unique (extension du client sur le serveur)
Fournit de la logique métier (calcul d’un taux, panier d’un client, etc.)
La durée de vie de l’EJB ne doit pas dépasser celle de son client
Représente la logique métier
Seuls EJB interfaçable par les clients
Les EJB session sans état
ne possède aucune information sur son client
ex : EJB relatif à une calculatrice
Les EJB session avec état
peut conserver des informations au nom de son client
ex : EJB relatif à un panier d’achat électronique
13. INSA - ASI InfoRep : EJB 13/65
Les EJB (4/11)
Variétés d’EJB : les EJB message
EJB producteur ou consommateur de messages
Utilisation de JMS (le server d’application est un JMS provider, et les
EJB sont des JMS client : JMS producer et JMS consumer)
Permet l’envoi de messages asynchrones
Permet l’envoi multiple (1 → n)
14. INSA - ASI InfoRep : EJB 14/65
Les EJB (5/11)
Les conteneurs EJB
Conteneur = environnement d’exécution pour un composant
Le composant se trouve dans le conteneur
Le conteneur fournit des services au composant
Conteneur se trouve dans un serveur d’applications qui lui fournit un
environnement d’exécution
Conteneur
EJB
web
Serveur d’applications
Conteneur
15. INSA - ASI InfoRep : EJB 15/65
Les EJB (6/11)
Les services des conteneurs EJB
Sans écrire une seule ligne de code
Persistance. Possibilité pour l’EJB d’être persistant dans une BD
Transactions déclaratives. Possibilité de gérer des transactions
complexes (sans utiliser l’API JTA -Java Transaction- et JTS -Java
Transaction Service-)
Mémoire cache. Possibilité d’améliorer les performances
Sécurité déclarative. Possibilité de gérer l’accès aux composants
Gestion d’erreurs. La spécification EJB définit la manière dont les
erreurs affectent les transactions, les résultats au niveau client, la
connexion et la restauration des composants
Portabilité. EJB = Spécification = possibilité de porter un EJB sur
un autre serveur plus puissant
16. INSA - ASI InfoRep : EJB 16/65
Les EJB (7/11)
Comment le conteneur fournit-il ces services ?
3 concepts de bases pour les EJB
Le concept de contrat
Services orthogonaux aux EJB
Interposition du conteneur entre le client et l’EJB
Contrat
Répartition des responsabilités entre chaque couche du logiciel
(Client, Conteneur, EJB, Gestionnaire de persistance (≥ 2.0))
Services orthogonaux
Le conteneur EJB fournit des services au programmeur
Le programmeur de l’EJB n’a plus qu’à respecter les règles pour
exploiter automatiquement ces services
Ces règles sont spécifiées dans le descripteur de déploiement
17. INSA - ASI InfoRep : EJB 17/65
Les EJB (8/11)
Interposition
Interposition : RMI et le design pattern Remote Proxy
Client
Stub
RMI
Réseau
Skeleton
RMI
Classe
d’interposition
générée
par
le
conteneur
Votre
EJB
1 Le client exécute un appel sur un Stub RMI
2 Ce stub RMI assemble et envoie des informations au serveur
3 Le skeleton désassemble les paramètres et les transmets au conteneur EJB
4 Le conteneur examine les références de sécurité de l’appelant de la méthode
5 Le conteneur démarre ou rejoint toute transaction nécessaire
6 Le conteneur exécute tous les appels nécessaires aux fonctions de persistance
7 Le conteneur déclenche diverses méthodes callback pour permettre au composant EJB d’acquérir des ressources
8 La méthode “logique métier” est appelée
9 Le conteneur exécute quelques autres tâches relatives aux transactions, à la persistance, aux méthodes callback
10 Le conteneur renvoie le résultat de la méthode métier ou une exception au client
18. INSA - ASI InfoRep : EJB 18/65
Les EJB (9/11)
Annotations Java
Intégrées au JDK 1.5, elles permettent d’ajouter des Méta-informations au code
(i.e. marquer des éléments Java afin de leur ajouter une propriété)
Peuvent être utilisées sur n’importe quel type d’élément Java (package, class,
attribut, méthode, paramètre, etc.)
Plusieurs annotations peuvent être utilisées sur un même élément
Non prises en compte par la JVM (mais présente dans le .class) : il faut écrire
du code ou des outils qui utilise ces informations
Utilisées à la compilation ou à l’exécution
Utilisation : @ suivi du mot-clef correspondant à l’annotation
L’API Java 5.0 propose de base 3 annotations : @Deprecated, @Override et
@SuppressWarnings
Déclaration et création de nouvelles annotations : comme une interface en
utilisant le mot-clef @interface (java.lang.annotation.Annotation)
Possibilité de passer des informations à une annotation : nom=valeur
19. INSA - ASI InfoRep : EJB 19/65
Les EJB (10/11)
Exemple d’annotations Java
Exemple
p u b l i c @interface MaNouvelleAnnotation {
}
Exemple
@ MaNouvelleAnnotation
@ SuppressWarnings (" deprecation ")
p u b l i c c l a s s maClasse {
@ UneAutreAnnotation (champ =" type ")
p u b l i c String texte = "Texte";
@Override
@ SuppressWarnings ({" deprecation "," unchecked "})
p u b l i c String toString () {
return t h i s .texte;
}
}
20. INSA - ASI InfoRep : EJB 20/65
Les EJB (11/11)
EJB3 et les annotations
Les EJB3 utilisent les annotations pour simplifier le code à produire :
Moins de code à écrire
Génération automatique des descripteurs de déploiement
21. INSA - ASI InfoRep : EJB 21/65
Les EJB Session sans état (1/7)
Description
EJB Session sans état (Stateless)
Composé d’une ou deux interfaces et d’une classe métier :
Interface de description du contrat pour accès distant
(XXRemote.java)
Utilisation de l’annotation @Remote (importation de
javax.ejb.Remote) juste avant la définition de l’interface
Interface de description du contrat pour accès local
(XXLocal.java)
Utilisation de l’annotation @Local (importation de
javax.ejb.Local) juste avant la définition de l’interface
Classe de définition de la logique métier (XXBean.java)
Importation de javax.ejb.Stateless
Utilisation de l’annotation @Stateless avant la définition de classe
Implémentation des interfaces précédentes
Ne pas être final
22. INSA - ASI InfoRep : EJB 22/65
Les EJB Session sans état (2/7)
Cycle de vie
1
Dans XXXBean.java
@PostConstruct suivi de la méthode postConstruct
@PreDestroy suivi de la méthode preDestroy
1. extrait du tutoriel de SUN : http://java.sun.com/j2ee/tutorial/1_3-fcs/
doc/EJBConcepts9.html
23. INSA - ASI InfoRep : EJB 23/65
Les EJB Session sans état (3/7)
Côté serveur
HelloStatelessRemote.java
package HelloWorld;
import javax.ejb.Remote;
@Remote
public i n t e r f a c e HelloStatelessRemote {
p u b l i c String sayHello(String s);
}
HelloStatelessLocal.java
package HelloWorld;
import javax.ejb.Local;
@Local
public i n t e r f a c e HelloStatelessLocal {
p u b l i c String sayHello(String s);
}
24. INSA - ASI InfoRep : EJB 24/65
Les EJB Session sans état (4/7)
Côté serveur
HelloStatelessBean.java
package HelloWorld;
import javax.ejb.Stateless;
@Stateless
public c l a s s HelloStatelessBean implements HelloStatelessLocal , HelloStatelessRemote {
p u b l i c String sayHello(String s) {
return "Hello " + s + " !";
}
}
@Local et @Remote peuvent être portées par la même interface
Il faut au moins une annotation @Local ou @Remote
Toutes les annotations peuvent éventuellement être placées
directement dans l’EJB. L’interface doit alors être précisé :
@Stateless
@Remote( NomInterface .class)
p u b l i c c l a s s EJBStateless implements NomInterface {
...
}
25. INSA - ASI InfoRep : EJB 25/65
Les EJB Session sans état (5/7)
Déploiement avec JBoss
Compilation et déploiement
A la compilation, inclure dans le classpath :
JBOSS_DIR/modules/javax/ejb/api/main/jboss-ejb-api_3.1_
spec-1.0.1.Final.jar (JBoss)
JBOSS_DIR/modules/system/layers/base/javax/ejb/api/main/
jboss-ejb-api_3.2_spec-1.0.0.Final.jar (WildFly)
Mettre dans un .jar
Pour déployer, déposer dans le répertoire
JBOSS DIR/server/JBOSS MODE/deploy (JBoss < 7)
JBOSS DIR/standalone/deployments (JBoss 7 et plus)
Arborescence des répertoires
HelloStateless.jar
|_ HelloWorld
| |_ HelloStatelessLocal.class
| |_ HelloStatelessBean.class
|_ META-INF
|_ MANIFEST.MF
26. INSA - ASI InfoRep : EJB 26/65
Les EJB Session sans état (6/7)
Côté client
Nommage d’un EJB
Service de nommage : JNDI
Nommage d’un EJB : ejb:AppName(ear)/ModuleName(jar)/BeanName!InterfaceName
Client.java
import javax.naming.Context;
import javax.naming. InitialContext ;
import java.util.Hashtable;
import HelloWorld. HelloStatelessRemote ;
p u b l i c c l a s s Client {
p u b l i c s t a t i c void main(String [] args) {
t r y {
Hashtable jndiProperties = new Hashtable ();
jndiProperties .put(Context.URL_PKG_PREFIXES , "org.jboss.ejb.client.naming");
Context context = new InitialContext ( jndiProperties );
HelloStatelessRemote obj = ( HelloStatelessRemote )context.lookup("ejb:/
HelloStateless / HelloStatelessBean !HelloWorld. HelloStatelessRemote ");
System.out.println(obj.sayHello(args [0]));
} catch (Exception e) {
System.out.println(e);
e. printStackTrace ();
}
}
}
27. INSA - ASI InfoRep : EJB 27/65
Les EJB Session sans état (7/7)
Exécution Client
À l’exécution, inclure dans le classpath :
JBOSS_DIR/bin/client/jboss-client.jar
jboss-ejb-client.properties
jboss-ejb-client.properties
endpoint.name = client -endpoint
remote. connectionprovider .create.options.org.xnio.Options. SSL_ENABLED = f a l s e
remote. connections = d e f a u l t
remote.connection. d e f a u l t .host = localhost
remote.connection. d e f a u l t .port = 8080
remote.connection. d e f a u l t .connect.options.org.xnio.Options. SASL_POLICY_NOANONYMOUS =
f a l s e
28. INSA - ASI InfoRep : EJB 28/65
Envoi d’exception (1/3)
Côté serveur
EJB : HelloStatelessBean.java
package HelloWorld;
import javax.ejb.Stateless;
@Stateless
public c l a s s HelloStatelessBean implements HelloStatelessRemote {
p u b l i c String sayHello(String s) throws ChaineVide {
i f (s.length () ==0) {
throw new ChaineVide ();
}
e l s e i f (s.equals("test")) {
s = "" + 1/0;
}
return "Hello " + s + " !";
}
}
29. INSA - ASI InfoRep : EJB 29/65
Envoi d’exception (2/3)
Côté serveur
Exception : ChaineVide.java
package HelloWorld;
p u b l i c c l a s s ChaineVide extends Exception {
p u b l i c ChaineVide (){
super ("String vide !");
}
}
Interface : HelloStatelessRemote.java
package HelloWorld;
import javax.ejb.Remote;
@Remote
public i n t e r f a c e HelloStatelessRemote {
p u b l i c String sayHello(String s) throws ChaineVide;
}
30. INSA - ASI InfoRep : EJB 30/65
Envoi d’exception (3/3)
Côté client
Client.java
import javax.naming.Context;
import javax.naming. InitialContext ;
import java.util.Hashtable;
import HelloWorld. HelloStatelessRemote ;
p u b l i c c l a s s Client {
p u b l i c s t a t i c void main(String [] args) {
t r y {
Hashtable jndiProperties = new Hashtable ();
jndiProperties .put(Context.URL_PKG_PREFIXES , "org.jboss.ejb.client.naming");
Context context = new InitialContext ( jndiProperties );
HelloStatelessRemote obj = ( HelloStatelessRemote )context.lookup("ejb:/
HelloException / HelloStatelessBean !HelloWorld. HelloStatelessRemote ");
i f (args.length >0)
System.out.println(obj.sayHello(args [0]));
e l s e
System.out.println(obj.sayHello(""));
} catch (Exception e) {
System.out.println(e);
e. printStackTrace ();
}
}
}
31. INSA - ASI InfoRep : EJB 31/65
Passage d’objets par valeur (1/4)
Côté serveur
Interface : HelloSerializableRemote.java
package HelloWorld;
import javax.ejb.Remote;
@Remote
public i n t e r f a c e HelloSerializableRemote {
p u b l i c String sayHello(Guy g);
}
EJB : HelloSerializableBean.java
package HelloWorld;
import javax.ejb.Stateless;
@Stateless
public c l a s s HelloSerializableBean implements HelloSerializableRemote {
p u b l i c String sayHello(Guy g) {
return "Hello " + g.getName () + " !";
}
}
32. INSA - ASI InfoRep : EJB 32/65
Passage d’objets par valeur (2/4)
Objet passé
Guy.java
package HelloWorld;
import java.io. Serializable ;
p u b l i c c l a s s Guy implements Serializable {
p r i v a t e String name;
p u b l i c Guy () { t h i s .name = ""; }
p u b l i c Guy(String name) { t h i s .name = name; }
p u b l i c String getName () {
return t h i s .name;
}
p u b l i c void setName(String name) {
t h i s .name = name;
}
}
34. INSA - ASI InfoRep : EJB 34/65
Passage d’objets par valeur (4/4)
Côté client
Client.java
import javax.naming.Context;
import javax.naming. InitialContext ;
import java.util.Hashtable;
import HelloWorld. HelloSerializableRemote ;
import HelloWorld.Guy;
p u b l i c c l a s s Client {
p u b l i c s t a t i c void main(String [] args) {
t r y {
Hashtable jndiProperties = new Hashtable ();
jndiProperties .put(Context.URL_PKG_PREFIXES , "org.jboss.ejb.client.naming");
Context context = new InitialContext ( jndiProperties );
HelloSerializableRemote obj = ( HelloSerializableRemote )context.lookup("ejb :/
HelloSerializable / HelloSerializableBean !HelloWorld. HelloSerializableRemote "
);
System.out.println(obj.sayHello(new Guy(args [0])));
} catch (Exception e) {
System.out.println(e);
e. printStackTrace ();
}
}
}
35. INSA - ASI InfoRep : EJB 35/65
Callbacks (1/6)
Exemple
Client Serveur
EJB
Programme Guy
File
-
-
Guy
File
-
-
Guy
Callback
Passage d’un stub RMI
36. INSA - ASI InfoRep : EJB 36/65
Callbacks (2/6)
Côté serveur
Interface : HelloCallbackRemote.java
package HelloWorld;
import javax.ejb.Remote;
import java.rmi. RemoteException ;
@Remote
public i n t e r f a c e HelloCallbackRemote {
p u b l i c String sayHello(Guy g) throws RemoteException ;
}
EJB : HelloCallbackBean.java
package HelloWorld;
import javax.ejb.Stateless;
import java.rmi. RemoteException ;
@Stateless
public c l a s s HelloCallbackBean implements HelloCallbackRemote {
p u b l i c String sayHello(Guy g) throws RemoteException {
return "Hello " + g.getName () + " !";
}
}
37. INSA - ASI InfoRep : EJB 37/65
Callbacks (3/6)
Interface du stub paramètre
Guy.java
package HelloWorld;
import java.io. Serializable ;
import java.rmi.Remote;
import java.rmi. RemoteException ;
p u b l i c i n t e r f a c e Guy extends Remote , Serializable {
p u b l i c String getName () throws RemoteException ;
p u b l i c void setName(String name) throws RemoteException ;
}
L’interface doit être accessible côté client et côté serveur
39. INSA - ASI InfoRep : EJB 39/65
Callbacks (5/6)
Implémentation du stub côté client uniquement
GuyImpl.java
package HelloWorld;
import java.io.*;
p u b l i c c l a s s GuyImpl implements Guy {
p u b l i c GuyImpl(String name) { t h i s .setName(name); }
p u b l i c String getName () {
String name = "";
String fichier = System.getProperty("user.dir") + "/GuyName";
t r y {
BufferedReader br = new BufferedReader (new InputStreamReader (new FileInputStream (
fichier)));
name = br.readLine ();
br.close ();
} catch ( IOException ioe){ ioe. printStackTrace (); }
return name;
}
p u b l i c void setName(String name) {
String adr = System.getProperty ("user.dir") + "/GuyName";
t r y {
BufferedWriter output=new BufferedWriter (new FileWriter(adr , f a l s e ));
output.write(name);
output.flush ();
output.close ();
} catch ( IOException ioe){ ioe. printStackTrace (); }
}
}
40. INSA - ASI InfoRep : EJB 40/65
Callbacks (6/6)
Côté client
Client.java
import javax.naming.Context;
import javax.naming. InitialContext ;
import java.util.Hashtable;
import java.rmi.server. UnicastRemoteObject ;
import HelloWorld. HelloCallbackRemote ;
import HelloWorld.Guy;
import HelloWorld.GuyImpl;
p u b l i c c l a s s Client {
p u b l i c s t a t i c void main(String [] args) {
t r y {
Hashtable jndiProperties = new Hashtable ();
jndiProperties .put(Context.URL_PKG_PREFIXES , "org.jboss.ejb.client.naming");
Context context = new InitialContext ( jndiProperties );
HelloCallbackRemote obj = ( HelloCallbackRemote )context.lookup("ejb :/
HelloCallback / HelloCallbackBean !HelloWorld. HelloCallbackRemote ");
Guy aGuy = new GuyImpl(args [0]) ,
stub = (Guy) UnicastRemoteObject . exportObject (aGuy ,0);
System.out.println(obj.sayHello(stub));
UnicastRemoteObject . unexportObject (aGuy , true );
} catch (Exception e) { System.out.println(e); }
}
}
41. INSA - ASI InfoRep : EJB 41/65
Les EJB Session avec état (1/6)
Description
EJB Session avec état (Stateful)
Composé d’une ou deux interfaces et d’une classe métier :
Interface de description du contrat pour accès distant
(XXRemote.java)
Utilisation de l’annotation @Remote (importation de
javax.ejb.Remote) juste avant la définition de l’interface
Interface de description du contrat pour accès local
(XXLocal.java)
Utilisation de l’annotation @Local (importation de
javax.ejb.Local) juste avant la définition de l’interface
Classe de définition de la logique métier (XXBean.java)
importation de javax.ejb.Stateful
Utilisation de l’annotation @Stateful avant la définition de la classe
Implémentation des interfaces précédentes
Ne pas être final
42. INSA - ASI InfoRep : EJB 42/65
Les EJB Session avec état (2/6)
Les EJB session avec état
Méthodes liées au cycle de vie
a
@PostConstruct suivi de la méthode postConstruct
@Init suivi de la méthode init
@PrePassivate suivi de la méthode prePassivate
@PostActivate suivi de la méthode postActivate
@Remove suivi de la méthode remove
@PreDestroy suivi de la méthode preDestroy
a. extrait du tutoriel de SUN : http://java.sun.com/j2ee/tutorial/1_
3-fcs/doc/EJBConcepts9.html
43. INSA - ASI InfoRep : EJB 43/65
Les EJB Session avec état (3/6)
Côté serveur
CounterStatefulLocal.java
package Stateful;
import javax.ejb.Local;
@Local
public i n t e r f a c e CounterStatefulLocal {
p u b l i c i n t count ();
}
CounterStatefulRemote.java
package Stateful;
import javax.ejb.Remote;
@Remote
public i n t e r f a c e CounterStatefulRemote {
p u b l i c i n t count ();
}
44. INSA - ASI InfoRep : EJB 44/65
Les EJB Session avec état (4/6)
Côté serveur
CounterStatefulBean.java
package Stateful;
import javax.ejb.Stateful;
@Stateful
public c l a s s CounterStatefulBean implements CounterStatefulLocal , CounterStatefulRemote
{
p r i v a t e i n t counter = 0;
p u b l i c i n t count () {
return ++ t h i s .counter;
}
}
Compteur session sans état
CounterStatelessLocal.class
CounterStatelessRemote.class
CounterStatelessBean.class
45. INSA - ASI InfoRep : EJB 45/65
Les EJB Session avec état (5/6)
Côté client
Attention !
Pour un EJB Stateful, une session JNDI doit être créée : on ajoute
"?stateful lors de la récupération du stub
Client.java
p u b l i c s t a t i c void main(String [] args) {
t r y {
Hashtable jndiProperties = new Hashtable ();
jndiProperties .put(Context.URL_PKG_PREFIXES , "org.jboss.ejb.client.naming");
Context context = new InitialContext ( jndiProperties );
CounterStatelessRemote stateless = ( CounterStatelessRemote )context.lookup("ejb
:/ Counter/ CounterStatelessBean !Stateless. CounterStatelessRemote ");
CounterStatefulRemote stateful = ( CounterStatefulRemote )context.lookup("ejb:/
Counter/ CounterStatefulBean !Stateful. CounterStatefulRemote ?stateful");
System.out.println("Decompte (stateless) : " + stateless.count ());
System.out.println("Decompte (stateless) : " + stateless.count ());
System.out.println("Decompte (stateful) : " + stateful.count ());
System.out.println("Decompte (stateful) : " + stateful.count ());
} catch (Exception e) {
System.out.println(e);
e. printStackTrace ();
}
}
48. INSA - ASI InfoRep : EJB 48/65
EJB/JSP (2/6)
Côté serveur
WebCounterInterface.java
package EJBCounter;
p u b l i c i n t e r f a c e WebCounterInterface {
p u b l i c i n t getCounter ();
}
WebCounterBean.java
package EJBCounter;
import javax.ejb.Stateless;
import javax.ejb.Local;
import javax.ejb.Remote;
@Remote(EJBCounter. WebCounterInterface .class)
@Stateless
public c l a s s WebCounterBean implements WebCounterInterface {
p r i v a t e s t a t i c i n t counter = 0;
p u b l i c i n t getCounter () {
WebCounterBean .counter ++;
return WebCounterBean .counter;
}
}
49. INSA - ASI InfoRep : EJB 49/65
EJB/JSP (3/6)
Côté client
Client.java
import javax.naming.Context;
import javax.naming. InitialContext ;
import java.util.Hashtable;
import EJBCounter. WebCounterInterface ;
p u b l i c c l a s s Client {
p u b l i c s t a t i c void main(String [] args) {
t r y {
Hashtable jndiProperties = new Hashtable ();
jndiProperties .put(Context.URL_PKG_PREFIXES , "org.jboss.ejb.client.naming");
Context context = new InitialContext ( jndiProperties );
WebCounterInterface counter = ( WebCounterInterface )context.lookup("ejb:
WebCounter/EJBCounter/ WebCounterBean !EJBCounter. WebCounterInterface ");
System.out.println("Decompte : " + counter.getCounter ());
} catch (Exception e) {
System.out.println(e);
e. printStackTrace ();
}
}
}
50. INSA - ASI InfoRep : EJB 50/65
EJB/JSP (4/6)
Archive Web
web.xml
<?xml v e r s i o n ="1.0" encoding="utf -8"?>
<!DOCTYPE web -app
PUBLIC " -//Sun Microsystems , Inc .// DTD Web Application 2.3// EN"
"http: // java.sun.com/dtd/web -app_2_3.dtd">
<web -app >
<display -name >Archive J2EE </display -name >
<description >
Partie Web de ma première application J2EE complète
</description >
</web -app >
52. INSA - ASI InfoRep : EJB 52/65
EJB/JSP (6/6)
Appel externe
counter.jsp
<%@ page contentType ="text/html; charset=UTF -8" %>
<%@ page import ="EJBCounter.WebCounterInterface , javax.naming. InitialContext "%>
<%!
p r i v a t e WebCounterInterface counter = n u l l ;
p u b l i c void jspInit () {
t r y {
counter = ( WebCounterInterface ) InitialContext .doLookup(
"ejb:WebCounter/EJBCounter/ WebCounterBean !EJBCounter. WebCounterInterface ");
} catch (Exception e) {
e. printStackTrace ();
}
}
%>
<html >
<head >
<title >JSP Counter </title >
</head >
<body >
<h1 >Hits: <%= counter.getCounter () %></h1 >
</body >
</html >
53. INSA - ASI InfoRep : EJB 53/65
Persistance (1/11)
Concepts
Les EJBs entité (Entity)
Le gestionnaire d’entités (entity manager)
détermine l’état de chaque objet :
créé mais non persistant (pas lié à un contexte de persistance)
persistant
détaché (sans lien avec le gestionnaire d’entités)
supprimé
peut être à la charge du conteneur (utilisation direct d’un
EntityManager via @PersistenceContext) ou de l’application
(création d’un EntityManager par l’intermédiaire une fabrique
-EntityManagerFactory- via @PersistenceUnit)
Le contexte de persistance
ensemble d’entités persistantes (par défaut dans une base de données
relationnelles)
54. INSA - ASI InfoRep : EJB 54/65
Persistance (2/11)
Les EJB entité
La classe représentant l’EJB entité doit
Utiliser les annotations @Entity, @Table et @Column
Posséder un constructeur par défaut en public ou protected
Ne pas être final
Implémenter Serializable si détaché
Être manipulable uniquement via les accesseurs (les attributs sont
private ou protected)
Posséder une clef primaire (annotation @Id) :
Si simple alors du type : type primitif, classe encapsulant type
primitif, String, Date (de java.util ou java.sql)
L’annotation @GeneratedValue permet de générer automatiquement
cette clef primaire
Implémenter hashCode, equals et toString
55. INSA - ASI InfoRep : EJB 55/65
Persistance (3/11)
Cycle de vie
2
2. extrait du tutoriel de SUN : http://java.sun.com/j2ee/tutorial/1_3-fcs/
doc/EJBConcepts9.html
56. INSA - ASI InfoRep : EJB 56/65
Persistance (4/11)
EJB Entité
Name.java
package helloWorld;
import javax.persistence .*;
import java.io. Serializable ;
@Entity
@Table(name =" names ")
public c l a s s Name implements Serializable {
@Id
@ GeneratedValue (strategy = GenerationType .IDENTITY)
p r i v a t e i n t id;
@Column(unique = true )
p r i v a t e String name;
p u b l i c Name () { t h i s .name = ""; }
p u b l i c Name (String name) { t h i s .name = name; }
p u b l i c i n t getId () { return t h i s .id; }
p u b l i c void setId ( i n t id) { t h i s .id = id; }
p u b l i c String getName () { return t h i s .name; }
. . .
57. INSA - ASI InfoRep : EJB 57/65
Persistance (5/11)
EJB Entité
Name.java
. . .
@Override
p u b l i c boolean equals(Object o) {
i f ( t h i s == o)
return true ;
i f (o == n u l l || getClass () != o.getClass ())
return f a l s e ;
Name that = (Name)o;
i f ( t h i s .name != n u l l ? ! t h i s .name.equals(that.name) : that.name != n u l l )
return f a l s e ;
return true ;
}
@Override
p u b l i c i n t hashCode () {
return t h i s .name != n u l l ? t h i s .name.hashCode () : 0;
}
@Override
p u b l i c String toString () {
return t h i s .name;
}
}
58. INSA - ASI InfoRep : EJB 58/65
Persistance (6/11)
EJB Session sans état
PersistentHelloBean.java
package helloWorld;
import javax.ejb.Stateless;
import javax.persistence .*;
import java.util.Collection;
import java.util.Iterator;
@Stateless
public c l a s s PersistentHelloBean implements PersistentHelloLocal , PersistentHelloRemote
{
@ PersistenceContext (unitName =" nameList ")
EntityManager em;
p u b l i c String sayHello(String s) {
String hello = "Hello " + s + " !";
Collection <Name > nameCollection ;
em.persist(new Name(s));
nameCollection = em.createQuery("from Name n"). getResultList ();
hello += "nListe des personnes déjà passées : ";
f o r (Iterator <Name >names= nameCollection .iterator (); names.hasNext (); ){
hello += " " + names.next ().getName ();
}
return hello;
}
}
59. INSA - ASI InfoRep : EJB 59/65
Persistance (7/11)
Association à une BD
Tout ORM doit être associé à une BD
Extérieure : Oracle, MySQL, PostgreSQL, etc.
Embarquée : dans l’application J2EE (partie EJB ou web), dans le
serveur d’application (H2, etc.)
Interfacé par JDBC, Hibernate et JTA
62. INSA - ASI InfoRep : EJB 62/65
Persistance (10/11)
JTA/H2
Utilisation (par exemple) de H2 comme BD embarquée
1 Création d’un utilisateur ”Admin” pour administrer JBOSS en mode
console Web
2 Création d’une ”Datasource JDBC”
3 Activer la Datasource
4 Déployer l’archive J2EE
Exemple
Name : ”nameList”
JNDI : ”java :jboss/datasources/nameListDS”
Driver : ”h2”
Connection URL : ”jdbc :h2 :/tmp/BD”
63. INSA - ASI InfoRep : EJB 63/65
Persistance (11/11)
Côté client
Client.java
import javax.naming.Context;
import javax.naming. InitialContext ;
import java.util.Hashtable;
import helloWorld. PersistentHelloRemote ;
p u b l i c c l a s s Client {
p u b l i c s t a t i c void main(String [] args) {
t r y {
Hashtable jndiProperties = new Hashtable ();
jndiProperties .put(Context.URL_PKG_PREFIXES , "org.jboss.ejb.client.naming");
Context context = new InitialContext ( jndiProperties );
PersistentHelloRemote obj = ( PersistentHelloRemote )context.lookup("ejb:/
PersistentHello / PersistentHelloBean !helloWorld. PersistentHelloRemote ");
System.out.println(obj.sayHello(args[args.length -1]));
} catch (Exception e) {
System.out.println(e);
e. printStackTrace ();
}
}
}
64. INSA - ASI InfoRep : EJB 64/65
Les EJB message
Description
3
Classe représentant l’EJB doit
implémenter l’interface javax.jms.MessageListener (donc
implémenter la méthode public void onMessage(Message m))
utiliser l’annotation @MessageDriven
ne pas être final
3. extrait du tutoriel de SUN : http://java.sun.com/j2ee/tutorial/1_3-fcs/
doc/EJBConcepts9.html
65. INSA - ASI InfoRep : EJB 65/65
Références
Programmation J2EE, Conteneurs J2EE, servlets, JSP et EJB :
S. Allamaraju, K. Avedal, R.Browett, J. Diamond, J. Griffin, M. Holden, A.
Hoskinson, R. Johson, T. Karsjens, L. Kim, A. Longshaw, T. Myers, A.
Nakimovsky, D. O’Connor, S. Tyagi, G. Van Damme, G. Van Huizen, M.
Wilcox, S. Zeiger
Eyrolles - ISBN : 2-212-09260-1
Enterprise JavaBeans :
Richard Monson-Haefel
O’Reilly 3ème édition - ISBN 0-596-00226-2
JBoss 3.0 deployment and Administration
Meeraj Moidoo Kunnumpurath
Wrox - ISBN 1-86100-812-0