You are on page 1of 32

Intergiciel et Construction dApplications Reparties

c
2007,
Cedric JOFFROY, Sebastien MOSSER, Michel RIVEILL
(version du 14 novembre 2008 - 11:13)

Chapitre9

Premiers pas J2EE


Lobjectif de cette annexe est de permettre `a chacun de se familiariser un peu avec une
plate-forme respectant les specifications J2EE (Java 2 Enterprise Edition). Pour cela nous
allons developper une petite application permettant `a chacun de gere ses cartes de visite
(ajout, suppression et consultation) et de les rendre accessibles aux autres utilisateurs (uniquement consultation). Pour atteindre ce but, lapplication se compose de deux parties :
le service dannuaire qui doit pouvoir etre utilisee `a distance et differentes applications
clientes de type client leger ou client lourd graphique ou en ligne de commande. Pour des
raisons de simplicite nous ne nous interesserons pas aux probl`emes lies `a lauthentification
des differentes classes dutilisateurs.
Pour mettre en uvrecette application nous allons utiliser :
un container managed entity bean pour gerer la persistance des cartes de visites,
un statefull session bean pour lajout et la suppression des cartes de visites,
un stateless session bean pour la consultation des cartes stockees,
un client lourd pour administrer lapplication et permettre lajout et la suppression
de cartes de visites
un client leger de consultation en utilisant une (servlet).
Une version html de ce texte est disponible `a ladresse http://rangiroa.polytech.
unice.fr/riveill/enseignement/tp/j2ee.html. Elle contiendra les evolutions futures
du sujet.

9.1

Les outils `
a utiliser

Parmis toutes les plates-formes J2EE disponible, nous avons fait le choix dutiliser
J2EE Jonas developpe par des equipes francaises dans le cadre du consortium ObjectWeb qui peut etre recupere sur le site web du consortium1 .
1

www.objectweb.com

9.1.1

CHAPITRE 9. PREMIERS PAS J2EE

Installation de Jonas

Linstallation proposee ici concerne la version 4.7.7 et sadresse aux utilisation dune
machine de type Linux ou Mac Os X. On laisse au lecteur attentif la modification de
cette procedure pour installer Jonas sur une plateforme Windows ou pour installer une
autre version de Jonas.
Nous allons installer Jonas dans le repertoire /opt/.
LINUX :~ > tar xvfz jonas4 .7.7 - tomcat5 .5.15. tgz
LINUX :~ > sudo mv JONAS_4_7_7 / opt /.

Pour fonctionner correctement, Jonas utiliser trois variables denvironnement qui


doivent etre correctement positionnee :
JONAS ROOT : chemin dacc`es au repertoire de Jonas,
PATH : chemin dacc`es aux binaires de Jonas,
CLASSPATH : doit contenir les deux archives necessaire au bon deroulement de ces
ateliers : ejb-2 1-api.jar et servlet-2 4.jar.
selon les versions Jonas, il peut y avoir dautres variables denvironneent : SPS= :
et JONAS BASE=JONAS ROOT

9.1.2

Installation dANT

Linstallation Ant est recommandee si lon veut tester les exemples fournis avec Jonas
et qui se trouve dans le repertoire /opt/JONAS 4 7 7/examples/src/. Ant est par exemple
disponible `
a lurl http://ant.apache.org/bindownload.cgi et sinstalle tr`es aisement.
LINUX :~ > unzip apache - ant -1.6.5 - bin . zip
LINUX :~ > sudo mv apache - ant -1.6.5 / opt /.

Comme pour Jonas, il est necessaire que la variable denvironnement ANT HOME
contienne le repertoire dinstallation de Ant.

9.1.3

Mise `
a jour des variables denvironnement

Pour etre certain de ne pas oublier une mise `a jour lors dune utilisation ulterieure,
nous vous invitons `
a regrouper celles-ci dans le fichier environnement.sh.
# !/ bin / sh
# Mise `
a jour des variables d environnemnts pour Jonas
JONAS_ROOT =/ opt / JONAS_4_7_7
echo " JONAS_ROOT set to $JONAS_ROOT "
PATH = $JONAS_ROOT / bin / unix : $PATH
echo " PATH set to $PATH "
CLASSPATH = $CLASSPATH : $JONAS_ROOT / lib / commons / j2ee / ejb -2 _1 - api . jar
CLASSPATH = $CLASSPATH : $JONAS_ROOT / lib / commons / j2ee / servlet -2 _4 . jar
echo " CLASSPATH set to $CLASSPATH "
# Mise `
a jour des variables d environnement pour Ant

9.2. GESTION DE LA PERSISTANCE - ENTITY BEAN

ANT_HOME =/ opt / apache - ant -1.6.5


echo " ANT_HOME set to $ANT_HOME "
export JONAS_ROOT ANT_HOME PATH CLASSPATH

Listing 9.1 Fichier environment.sh


Il ne reste plus qu`
a executer ce shell `a laide de la commande source pour saffranchir
du dialecte utilise (zsh, tcsh ou bash) :
LINUX :~ > source environnement . sh

9.1.4

Pour tester linstallation

Avant toutes autres manipulation, un test de linstallation simpose. Suivez attentivement les differents messages derreurs.
LINUX :~ > jonas check
LINUX :~ > jonas start

1. Le check verifie letat de linstallation, et peut renvoyer des warnings, rien de bien
grave.
2. Le start lance le serveur Jonas. Lorsque le lancement est termine, il rend la main
en indiquant quil `
a demarre.

9.2

Gestion de la persistance - entity bean

Les objets persistants sont les cartes de visites. Nous allons donc les implementer sous
la forme dentity bean dont la persistance est directement geree par le container. Avant
decrire lentity bean, construisons la base de donnees.

9.2.1

La base de donn
ees

Pour conserver les cartes de visite nous allons utiliser une base de donnee qui contiendra
une seule table CARTEDEVISITE structuree de la mani`ere suivante :
un id permettant didentifier de mani`ere unique chacune des cartes de visite,
un nom,
un prenom,
une adresse mail,
un numero de telephone.
Tous ces champs sont de type varchar et sont non nuls, `a lexception du champ id qui
est de type identity (shortcut pour un integer primary key dans le SGBD utilise).
Nous utiliserons le micromoteur de base de donnees HSQLDB, livre avec Jonas. Les
informations de connexion sont les suivantes
urlid localhost - dbjonas
url jdbc : hsqldb : hsql :// localhost :9001/ db_jonas
username jonas

CHAPITRE 9. PREMIERS PAS J2EE

password jonas

Listing 9.2 Fichier sql-rc.conf

Description du sch
ema relationnel
1

drop table if exists CARTEDEVISITE ;


create table CARTEDEVISITE (
ID
IDENTITY ,
NOM
varchar (255)
PRENOM
varchar (255)
EMAIL
varchar (255)
PHONE
varchar (255)
);

not
not
not
not

null ,
null ,
null ,
null

Listing 9.3 Fichier database.sql

Chargement de la relation dans le moteur

LINUX :~ > java - jar $JONAS_ROOT / lib / commons / jonas / hsqldb . jar \
-- autoCommit -- continueOnErr \
-- rcfile ./ sql - rc . conf localhost - dbjonas database . sql

Script de chargement automatique


Pour simplifier linitialisation de la base de donnees, on met en place un script qui
permet dexecuter cette ligne de commande :
2

# !/ bin / sh
echo " Database initialization "
java - jar $JONAS_ROOT / lib / commons / jonas / hsqldb . jar \
-- autoCommit -- continueOnErr \
-- rcfile ./ sql - rc . conf localhost - dbjonas database . sql

Listing 9.4 Fichier initDatabase.sh


Pour executer ce script (apr`es lavoir rendu executable . . .) :
LINUX :~ > ./ initDatabase . sh

On dispose maintenant dune relation vide dans le moteur de base de donnees HSQL.
Si vous netes pas convaincu, lancez le client graphique Hsql Manager sans toucher au
mot de passe :
LINUX :~ > java - cp $JONAS_ROOT / lib / commons / jonas / hsqldb . jar org . hsqldb . util . DatabaseManager

9.2. GESTION DE LA PERSISTANCE - ENTITY BEAN

9.2.2

Ecriture du container managed entity bean

Le code dun entity bean est reparti dans plusieurs classes Java et descripteurs :
Remote Interface : linterface qui definit les differentes methodes du Bean qui seront
accessibles pour les clients,
Home Interface : linterface qui est visible par le client pour creer, retrouver puis
manipuler des instances du Bean,
la classe dimplementation du Bean,
deux descripteurs de deploiement indiquant entre autre le mapping objet
relationnel `
a utiliser pour garantir la persistance des objets, et les requetes permettant de les retrouver.
Interface remote : on decrit dans cette interface les fonctions permettant de manipuler
les cartes de visite.
package carte_cmp ;

import javax . ejb . EJBObject ;


import java . rmi . RemoteException ;
public interface CarteDeVisiteCMP extends EJBObject {

14

19

public
public
public
public
public

Integer getId () throws RemoteException ;


String getNom () throws RemoteException ;
String getPrenom () throws RemoteException ;
String getEmail () throws RemoteException ;
String getPhone () throws RemoteException ;

// Pas
public
public
public
public

de setId , le SGBD la genere .


void setPrenom ( String prenom ) throws RemoteException ;
void setNom ( String nom ) throws RemoteException ;
void setEmail ( String email ) throws RemoteException ;
void setPhone ( String phone ) throws RemoteException ;

Listing 9.5 Fichier CarteDeVisiteCMP.java

Interface Home : cette interface, accessible par les clients de lapplication, permet
de retouver les instances de cartes de visites, den creer, . . .. Les instances quelle renvoie
sont du type de linterface precedente, ce qui masque aux clients limplementation reelle
du Bean.
1

package carte_cmp ;
import java . rmi . RemoteException ;
import javax . ejb .*;
import java . util .*;

public interface CarteDeVisiteCMPHome extends EJBHome {


public CarteDeVisiteCMP
create ( String nom , String prenom , String email , String phone )

CHAPITRE 9. PREMIERS PAS J2EE

throws RemoteException , CreateException ;

11

public CarteDeVisiteCMP findByPrimaryKey ( Integer id )


throws RemoteException , FinderException ;
public Collection findByNom ( String nom )
throws RemoteException , FinderException ;

16

public Collection findByPrefix ( String prefix )


throws RemoteException , FinderException ;
21

Listing 9.6 Fichier CarteDeVisiteCMPHome.java


Impl
ementation du bean Le choix dutiliser un CMP entity bean simplifie grandement
la mise en oeuvre puis que la plupart des methodes nont pas besoin detre implementees
et seront generees `
a partir des fichiers de deploiement.
package carte_cmp ;

14

19

24

29

34

import
import
import
import
import

java . sql .*;


javax . sql .*;
java . util .*;
javax . ejb .*;
javax . naming .*;

public abstract class CarteDeVisiteCMPBean implements EntityBean {


/* * Abstract == > gere par le conteneur * */
public abstract Integer getId ();
public abstract void setId ( Integer id );
public abstract String getNom ();
public abstract void setNom ( String nom );
public abstract String getPrenom ();
public abstract void setPrenom ( String prenom );
public abstract String getEmail ();
public abstract void setEmail ( String email );
public abstract String getPhone ();
public abstract void setPhone ( String phone );
// Cree le composant et le sauvegarde dans la base de donnees avec
// un insert
public Integer
ejbCreate ( String nom , String prenom , String email , String phone )
throws CreateException {
// renseigne les propriete du composant
setNom ( nom );
setPrenom ( prenom );
setEmail ( email );
setPhone ( phone );
return null ;
}
public void
ejbPostCreate ( String nom , String prenom ,

9.2. GESTION DE LA PERSISTANCE - ENTITY BEAN

String email , String phone ) {


// Dans le cas de tables de liaisons , on instancierait les
// liaisons ici .

39

49

// les methodes suivantes n ont pas besoin d etre implemante dans


// le cadre d un CMP entity bean
public void ejbRemove () throws RemoveException { }
public void setEntityContext ( EntityContext context ) {
this . context = context ;
}
public void unsetEntityContext () { this . context = null ; }

54

public
public
public
public

44

void
void
void
void

ejbActivate () { }
ejbPassivate () { }
ejbLoad () { }
ejbStore () { }

Listing 9.7 Fichier CarteDeVisiteCMPBean.java


La cle primaire utilisee sera de type auto incrementee (par la base de donnee). Nous
nutiliserons donc jamais la methode setId().
TODO pourquoi alors mettre cette methode ? on a besoin de loperation setId car le
generateur de code rale si elle ny est pas. Reste `
a le reverifier.
Descripteur de d
eploiement J2EE : ce fichier est commun `a tous les serveur dapplications J2ee et permet de preciser le mapping `a utiliser entre lentity bean et la base
de donnee.

10

15

20

25

<? xml version ="1.0" encoding =" ISO -8859 -1"? >
<ejb - jar >
< description > Descripteur de deploiement pour l EJB carte de visite
</ description >
< display - name > EJB CarteDeVisite </ display - name >
< enterprise - beans >
< entity >
< description > EJB CarteDeVisite ( CMP ) </ description >
<ejb - name > CarteDeVisiteCMP </ ejb - name >
< home > carte_cmp . CarteDeVisiteCMPHome </ home >
< remote > carte_cmp . CarteDeVisiteCMP </ remote >
<ejb - class > carte_cmp . CarteDeVisiteCMPBean </ ejb - class >
< persistence - type > Container </ persistence - type >
< prim - key - class > java . lang . Integer </ prim - key - class >
< reentrant > False </ reentrant >
< abstract - schema - name > cartedevisite </ abstract - schema - name >
<cmp - field >
< field - name > id </ field - name >
</ cmp - field >
<cmp - field >
< field - name > nom </ field - name >
</ cmp - field >
<cmp - field >
< field - name > prenom </ field - name >
</ cmp - field >

30

35

40

45

50

55

60

65

70

75

CHAPITRE 9. PREMIERS PAS J2EE

<cmp - field >


< field - name > email </ field - name >
</ cmp - field >
<cmp - field >
< field - name > phone </ field - name >
</ cmp - field >
< primkey - field > id </ primkey - field >
< query >
< query - method >
< method - name > findByNom </ method - name >
< method - params >
< method - param > java . lang . String </ method - param >
</ method - params >
</ query - method >
<ejb - ql > SELECT OBJECT ( o ) FROM cartedevisite o
WHERE o . nom = ?1
</ ejb - ql >
</ query >
< query >
< query - method >
< method - name > findByPrefix </ method - name >
< method - params >
< method - param > java . lang . String </ method - param >
</ method - params >
</ query - method >
<ejb - ql > SELECT OBJECT ( o ) FROM cartedevisite o
WHERE LOCATE (?1 , o . nom ) > 0
</ ejb - ql >
</ query >
< query >
< query - method >
< method - name > findByPrimaryKey </ method - name >
< method - params >
< method - param > java . lang . Integer </ method - param >
</ method - params >
</ query - method >
<ejb - ql > SELECT OBJECT ( o ) FROM cartedevisite o
WHERE o . id = ?1
</ ejb - ql >
</ query >
</ entity >
</ enterprise - beans >
< assembly - descriptor >
< container - transaction >
< method >
<ejb - name > CarteDeVisiteCMP </ ejb - name >
< method - name >* </ method - name >
</ method >
< trans - attribute > Required </ trans - attribute >
</ container - transaction >
</ assembly - descriptor >
</ ejb - jar >

Listing 9.8 Fichier ejb-jar.xml

9.2. GESTION DE LA PERSISTANCE - ENTITY BEAN

Descripteur Jonas : En complement du descripteur J2EE, chaque fournisseur de plateforme propose son propre descripteur afin de completer la description initiale. Dans Jonas,
il permet de decrire lutilisation des ressources tierces comme par exemple lacc`es `a la base
de donnees.
1

11

16

21

26

31

<? xml version ="1.0" encoding =" ISO -8859 -1"? >
< jonas - ejb - jar >
< jonas - entity >
<ejb - name > CarteDeVisiteCMP </ ejb - name >
< jndi - name > MyCarteDeVisiteCMP </ jndi - name >
< jdbc - mapping >
< jndi - name > jdbc_1 </ jndi - name >
< jdbc - table - name > CARTEDEVISITE </ jdbc - table - name >
< automatic - pk > true </ automatic - pk >
<cmp - field - jdbc - mapping >
< field - name > id </ field - name >
< jdbc - field - name > ID </ jdbc - field - name >
</ cmp - field - jdbc - mapping >
<cmp - field - jdbc - mapping >
< field - name > nom </ field - name >
< jdbc - field - name > NOM </ jdbc - field - name >
</ cmp - field - jdbc - mapping >
<cmp - field - jdbc - mapping >
< field - name > prenom </ field - name >
< jdbc - field - name > PRENOM </ jdbc - field - name >
</ cmp - field - jdbc - mapping >
<cmp - field - jdbc - mapping >
< field - name > phone </ field - name >
< jdbc - field - name > PHONE </ jdbc - field - name >
</ cmp - field - jdbc - mapping >
<cmp - field - jdbc - mapping >
< field - name > email </ field - name >
< jdbc - field - name > EMAIL </ jdbc - field - name >
</ cmp - field - jdbc - mapping >
</ jdbc - mapping >
</ jonas - entity >
</ jonas - ejb - jar >

Listing 9.9 Fichier jonas-ejb-jar.xml

9.2.3

Compilation et d
eploiement de lentity bean

Nous avons maintenant tout ce qui est necessaire pour compiler et deployer lentity
bean. A lissue de cette premi`ere etape nous avons larborescence suivante :

+ - - > bin /
+ - - > META - INF /
+ - - > ejb - jar . xml
+ - - > jonas - ejb - jar . xml
+ - - > src /
+ - - > CarteDeVisiteCMPBean . java
+ - - > CarteDeVisiteCMPHome . java
+ - - > CarteDeVisiteCMP . java
+ - - > Test . java

10

CHAPITRE 9. PREMIERS PAS J2EE

Nous conserverons cette arborescence pour les autres beans que nous creerons. Le
repertoire bean contiendra toujours le code compile des fichiers java et le repertoire
bin/META-INF, les descripteurs.
Pour pouvoir etre execute par Jonas, un bean a besoin detre contenu dans une archive
qui facilite son deploiement. Pour cela, on gen`ere le bytecode, puis on ecrit les descripteur
de deploiement et on archive lensemble dans un fichier jar.
1

LINUX :~/ CarteDeVisite > javac -d bin src /*. java


LINUX :~/ CarteDeVisite > cp *. xml bin / META - INF /.
LINUX :~/ CarteDeVisite > cd bin
LINUX :~/ CarteDeVisite / bin > jar cf ../ CarteDeVisiteCMP . jar
LINUX :~/ CarteDeVisite / bin > cd ..
LINUX :~/ CarteDeVisite >

Deployer un bean dans Jonas se fait en deux etapes :


deposer larchive dans le repertoire ejbjars de Jonas,
utiliser loutils dadministration de Jonas pour publier le bean.

LINUX :~/ CarteDeVisite > cp CarteDeVisiteCMP . jar $JONAS_ROOT / ejbjars /.


LINUX :~/ CarteDeVisite > cd $JONAS_ROOT / ejbjars
LINUX :/ opt / JONAS_4_7_7 / ejbjars > jonas admin -a CarteDeVisiteCMP . jar
LINUX :/ opt / JONAS_4_7_7 / ejbjars > cd LINUX :~/ CarteDeVisite >

9.2.4

Client dun entity bean

Ce client, non essentiel `


a lapplication, permet de valider le code de lentity bean. Nous
faisons le choix dimplementer un client simple qui cree deux entity bean, effectue une
recherche par nom et une recherche `a laide dun prefixe.
package carte_cmp ;

import
import
import
import

java . util . Properties ;


javax . naming . InitialContext ;
javax . naming . Context ;
javax . rmi . PortableRemoteObject ;

import java . util . Collection ;


import java . util . Iterator ;
10

public class Test {


public static void main ( String args []) {
15

try {
// Recherche de l interface home de l EJB
Context initialContext = new InitialContext ();
Object objref = initialContext . lookup ( " MyCarteDeVisiteCMP " );

20

// Reference a l interface locale de l EJB


C arteDeVisiteCMPHome home = ( CarteDeVisiteCMPHome )
PortableRemoteObject . narrow ( objref , CarteDeVisiteCMPHome . class );

9.2. GESTION DE LA PERSISTANCE - ENTITY BEAN

11

// Creation deux carte de visite dans la base de donnees


CarteDeVisiteCMP toto =
home . create ( " TOTO " , " toto " , " toto@toto " , " 0123456 " );
CarteDeVisiteCMP titi =
home . create ( " TITI " , " titi " , " titi@titi " , " 9876443 " );

25

30

// Objet de type client pour faire nos tests


CarteDeVisiteCMP test ;
// Recherche par le nom de la personne
System . out . println ( " Liste des clients qui ont pour nom TOTO : " );
Collection cl = home . findByNom ( " TOTO " );
Iterator iLast = cl . iterator ();
while ( iLast . hasNext ()) {
test = iLast . next ();
System . out . println ( " ->" + test . getPrenom ());
}

35

40

// Recherche par le prefixe de la personne


System . out . println ( " Liste des clients qui ont pour prefixe T : " );
Collection c2 = home . findByPrefix ( " T " );
Iterator iLast1 = c2 . iterator ();
while ( iLast1 . hasNext ()) {
test = iLast1 . next ();
System . out . println ( " ->" + test . getPrenom ());
}

45

50

} catch ( Exception e ) {
System . err . println ( " Erreur : " + e );
System . exit (2);
}

55

}
}

Listing 9.10 Fichier Test.java

9.2.5

Compilation et ex
ecution du client

Apr`es avoir compile le client, nous utilisons pour lexecuter, lutilitaire jclient qui
permet lexecution du client dans le contexte de Jonas et davoir ainsi lacc`es `a lannuaire
de referencement JNDI dans lequel sont enregistres tous les beans publies dans Jonas.
Nous consid`ererons que le client poss`ede dans son CLASSPATH le jar du bean, pour pouvoir utiliser le proxy (classe RemoteStub generee par genic) permettant dacc`eder au bean
comme un objet distant. Pour travailler proprement, il serait beaucoup plus judicieux de
donner au client soit le proxy, soit une mani`ere de le generer.
1

LINUX :~/ CarteDeVisite > jclient \


- cp $JONAS_ROOT / ejbjars / CarteDeVisiteCMP . jar \
- argclient carte_cmp . Test
ClientContainer . info : Starting client ...
Liste des clients qui ont pour nom TOTO :
-> toto

12

CHAPITRE 9. PREMIERS PAS J2EE

Liste des clients qui ont pour prefixe T :


-> toto
-> titi

9.2.6

Automatisation des t
aches r
ep
etitives

La compilation, le deployement et la publication dun bean, ainsi que la compilation


et lexecution dun client sont des t
aches repetitives quil est aise dautomatiser. Voici un
exemple de script bash qui rendra la suite de lennonce beaucoup plus lisible. Ce script
permet :
de compiler et generer larchive dun bean (compile),
de le deployer et de le publier (load),
de compiler et dexecuter un client (run),
de retirer le bean publie (unload),
et de nettoyer les sources (clean).
TODO valider le script pour tcsh
1

# !/ bin / sh
# ATTENTION : fonctionne en bash , zsh

JAR_NAME = CarteDeVisiteCMP . jar


CLIE NT_CLASS_NAME = carte_cmp . Test
# ## DO NOT EDIT AFTER THIS LINE !! ###
export JAR_NAME CLIENT_CLASS_NAME

11

16

function compile () {
echo " ## src --> bin compilation "
javac -d bin src /*. java
echo " ## Deploying xml descriptors "
cp *. xml bin / META - INF /.
echo " ## Building $JAR_NAME "
cd bin
jar cf ../ $JAR_NAME *
cd ..
}

21

26

31

36

function load () {
echo " ## Moving $JAR_NAME --> $JONAS_ROOT / ejbjars "
mv $JAR_NAME $JONAS_ROOT / ejbjars /.
echo " ## Loading $JAR_NAME in JONAS "
cd $JONAS_ROOT / ejbjars
jonas admin -a $JAR_NAME
cd }
function unload () {
echo " ## Unloading $JAR_NAME from JONAS "
cd $JONAS_ROOT / ejbjars
jonas admin -r $JAR_NAME
cd }

9.2. GESTION DE LA PERSISTANCE - ENTITY BEAN

41

46

51

56

61

13

function run () {
echo " ## Runnning client ... "
jclient - cp $JONAS_ROOT / ejbjars / $JAR_NAME - argclient $CLIENT_CLASS_NAME
}
function clean () {
echo " ## Cleaning directories "
rm - rf *~ *. jar src /*~ bin /*
mkdir bin / META - INF
}
function main () {
case $1 in
" compile " ) compile ;;
" load " )
load ;;
" unload " ) unload ;;
" run " )
run ;;
" clean " )
clean ;;
" all " )
unloand ; clean ; compile ; load ; run ;;
*) " Unknown Command : [ $1 ] " ;;
esac
}
main $@

Listing 9.11 Fichier manage.sh


La gestion dun bean devient simple. Il suffit de modifier lentete pour indique le nom
du bean et le nom du client et dexecuter ce script en precisant laction a effectuer.

14

19

LINUX :~/ CarteDeVisite > ./ manage . sh clean


# # Cleaning directories
LINUX :~/ CarteDeVisite > ./ manage . sh compile
# # src --> bin compilation
# # Deploying xml descriptors
# # Building CarteDeVisiteCMP . jar
LINUX :~/ CarteDeVisite > ./ manage . sh load
# # Moving CarteDeVisiteCMP . jar --> / opt / JONAS_4_7_7 / ejbjars
# # Loading CarteDeVisiteCMP . jar in JONAS
LINUX :~/ CarteDeVisite > ./ manage . sh run
# # Runnning client ...
ClientContainer . info : Starting client ...
Liste des clients qui ont pour nom TOTO :
-> toto
-> toto
Liste des clients qui ont pour prefixe T :
-> toto
-> titi
-> toto
-> titi
LINUX :~/ CarteDeVisite > ./ manage . sh unload
# # Unloading CarteDeVisiteCMP . jar from JONAS

Note : Nous utiliserons systematiquement ce script par la suite.

14

CHAPITRE 9. PREMIERS PAS J2EE

9.3

La partie m
etier - statefull session bean

9.3.1

Principe

Dans le cadre dune architecture n tiers, il nest pas pensable doffrir aux differents
clients la possibilite de manipuler directement les entity beans qui representent des donnees
dans la base de donnees. En effet, les acc`es sont trop elementaires. Nous allons encapsuler
la logique metier de lapplication dans un session bean.
Les operations dajout et de supression de cartes etant critiques nous allons uniquement les autoriser pour ladministrateur de lapplication `a laide dun bean de session `a
etat (statefull session bean), dans lequel on positionnera un etat estIdentifie. Lexecution
des actions dajout et de suppression sera autorisee uniquement pour les utilisateurs authentifies.

9.3.2

Ecriture du statefull session bean

Comme pour un entity bean, lecriture dun session bean demande lecriture de deux
interfaces (linterface remote et linterface home), dune classe java implementant le bean
et de deux descripteurs de configuration (celui present dans toutes plates-formes J2EE et
celui de Jonas).
Interface remote
package administrators ;
3

import javax . ejb . EJBObject ;


import java . rmi . RemoteException ;
public interface Administrator extends EJBObject {
// Log into the bean
public boolean login ( String username , String password )
throws RemoteException ;
// Log out from the bean
public boolean logout () throws RemoteException ;

13

// Add a CarteDeVisite inside the system


public boolean add ( String nom , String prenom ,
String mail , String phone )
throws RemoteException ;
18

// Delete a card , using the id to retrieve the good one


public boolean delete ( int id ) throws RemoteException ;
}

Listing 9.12 Fichier Administrator.java

Interface home


9.3. LA PARTIE METIER
- STATEFULL SESSION BEAN

15

package administrators ;
3

import java . rmi . RemoteException ;


import javax . ejb . CreateException ;
import javax . ejb . EJBHome ;
public interface AdministratorHome extends EJBHome {
// Constructeur par defaut
Administrator create () throws RemoteException , CreateException ;
// Permet de se logger directement a la creation
Administrator create ( String username , String password )
throws RemoteException , CreateException ;

13

Listing 9.13 Fichier AdministratorHome.java

Impl
ementation du session bean
package administrators ;

import java . rmi . RemoteException ;


import javax . ejb . SessionBean ;
import javax . ejb . SessionContext ;
import javax . rmi .*;
import javax . naming . InitialContext ;
import javax . naming . Context ;

10

import java . util .*;


import carte_cmp .*;
15

public class AdministratorBean implements SessionBean {


private boolean isLogged ;

25

public boolean login ( String username , String password ) {


if ( username . equals ( " admin " ) && password . equals ( " admin " )) {
this . isLogged = true ;
return true ;
}
return false ;
}

30

public boolean logout () {


this . isLogged = false ;
return true ;
}

20

public boolean add ( String nom , String prenom , String mail , String phone ) {
try {
if ( isLogged ) {

16

CHAPITRE 9. PREMIERS PAS J2EE

Context initialContext = new InitialContext ();


Object objref = initialContext . lookup ( " MyCarteDeVisiteCMP " );

35

// Reference a l interface locale de l EJB


CarteDeVisiteCMPHome home = ( CarteDeVisiteCMPHome )
PortableRemoteObject . narrow ( objref ,
CarteDeVisiteCMPHome . class );

40

// Objet de type CarteDeVisite , avec creation de cet objet


CarteDeVisiteCMP test = home . create ( nom , prenom , mail , phone );
45

return true ;
} else return false ;
}
catch ( Exception e ) {
System . err . println ( " Erreur : " + e );
}
return false ;

50

}
55

public boolean delete ( int id ) {


try {
if ( isLogged ) {
Context initialContext = new InitialContext ();
Object objref = initialContext . lookup ( " MyCarteDeVisiteCMP " );

60

// Reference a l interface locale de l EJB


CarteDeVisiteCMPHome home = ( CarteDeVisiteCMPHome )
PortableRemoteObject . narrow ( objref ,
CarteDeVisiteCMPHome . class );
65

// Objet de type CarteDeVisite , en vue de le supprimer


// de la table
CarteDeVisiteCMP test = home . findByPrimaryKey ( id );
if ( test != null ){
test . remove ();
return true ;
} else return false ;
} else return false ;

70

}
catch ( Exception e ) {
System . err . println ( " Erreur : " + e );
}
return false ;

75

}
80

public void ejbCreate ()

85

90

{ this . isLogin = false ; }

public void ejbCreate ( String username , String password ) {


if ( username . equals ( " admin " ) && password . equals ( " admin " ))
this . isLogin = true ;
else
this . isLogin = false ;
}
public void ejbRemove () {}


9.3. LA PARTIE METIER
- STATEFULL SESSION BEAN

public void ejbActivate () {}


public void ejbPassivate () {}
public void setSessionContext ( SessionContext sc ) {}
95

Listing 9.14 Fichier AdministratorBean.java

Descripteur J2EE

10

15

20

25

<? xml version ="1.0" encoding =" ISO -8859 -1"? >
<ejb - jar >
< description > Descripteur de deploiement du bean administratif
</ description >
< display - name > Administrator </ display - name >
< enterprise - beans >
< session >
< description > Administrator </ description >
< display - name > Administrator </ display - name >
<ejb - name > Administrator </ ejb - name >
< home > administrators . AdministratorHome </ home >
< remote > administrators . Administrator </ remote >
<ejb - class > administrators . AdministratorBean </ ejb - class >
< session - type > Stateful </ session - type >
< transaction - type > Container </ transaction - type >
</ session >
</ enterprise - beans >
< assembly - descriptor >
< container - transaction >
< method >
<ejb - name > Administrator </ ejb - name >
< method - name >* </ method - name >
</ method >
< trans - attribute > Required </ trans - attribute >
</ container - transaction >
</ assembly - descriptor >
</ ejb - jar >

Listing 9.15 Fichier ejb-jar.xml

Descripteur Jonas

<? xml version ="1.0" encoding =" ISO -8859 -1"? >
< jonas - ejb - jar >
< jonas - session >
<ejb - name > Administrator </ ejb - name >
< jndi - name > MyAdministrator </ jndi - name >
</ jonas - session >
</ jonas - ejb - jar >

Listing 9.16 Fichier jonas-ejb-jar.xml

17

18

CHAPITRE 9. PREMIERS PAS J2EE

9.3.3

Ecriture dun client du session bean

Comme pour lentity bean, nous allons construire un client capable de se connecter au
session bean precedemment decrit.
package administrators ;
3

import
import
import
import

java . util . Properties ;


javax . naming . InitialContext ;
javax . naming . Context ;
javax . rmi . PortableRemoteObject ;

import
import
import
import
import

java . io . BufferedReader ;
java . io . InputStreamReader ;
java . io . IOException ;
java . io . OutputStreamWriter ;
java . io . PrintWriter ;

13

import java . util .*;


import carte_cmp .*;

18

public class AdministratorClient {


public static void main ( String args []) {
try {

23

28

33

38

43

48

InputStreamReader isr = new InputStreamReader ( System . in );


BufferedReader br = new BufferedReader ( isr );
boolean isQuit = false ;
// Recherche de l interface home de l EJB
Context initialContext = new InitialContext ();
Object objref = initialContext . lookup ( " MyAdministrator " );
// Reference a l interface locale de l EJB
AdministratorHome home = ( AdministratorHome )
PortableRemoteObject . narrow ( objref ,
AdministratorHome . class );
// Creation d un administrateur
Administrator myAdministrator = home . create ();
while ( isQuit == false ) {
System . out . println ( " 1. Connexion " );
System . out . println ( " 2. Quitter " );
System . out . println ( " >" );
String principalChoice = null ;
principalChoice = br . readLine ();
if ( principalChoice . equals ( " 2 " )){
isQuit = true ;
System . out . println ( " Bye bye ... " );
}
else if ( principalChoice . equals ( " 1 " )){
System . out . println ( " Username : " );
String username = null ;


9.3. LA PARTIE METIER
- STATEFULL SESSION BEAN

19

username = br . readLine ();


53

58

63

68

73

78

83

88

93

98

103

System . out . println ( " Password : " );


String password = null ;
password = br . readLine ();
if ( myAdministrator . login ( username , password )){
boolean isLog = true ;
while ( isLog == true ){
System . out . println ( " 1. Ajouter une carte "
+ " de visite " );
System . out . println ( " 2. Retirer une carte "
+ " de visite " );
System . out . println ( " 3. Se deconnecter " );
System . out . println ( " >" );
String secondaryChoice = null ;
secondaryChoice = br . readLine ();
if ( secondaryChoice . equals ( " 1 " )){
System . out . println ( " Ajout d une "
+ " carte de visite ... " );
System . out . println ( " Entrer le nom : " );
String nom = null ;
nom = br . readLine ();
System . out . println ( " Entrer le prenom : " );
String prenom = null ;
prenom = br . readLine ();
System . out . println ( " Entrer le mail : " );
String mail = null ;
mail = br . readLine ();
System . out . println ( " Entrer le numero de "
+ " tel : " );
String phone = null ;
phone = br . readLine ();
boolean isAdd = myAdministrator . add ( nom ,
prenom ,
mail ,
phone );
if ( isAdd ){
System . out . println ( " Ajout reussi ... " );
}
else {
System . out . println ( " Ajout echoue ... " );
}
}
else if ( secondaryChoice . equals ( " 2 " )){
System . out . println ( " Suppression d une "
+ " carte de visite ... " );
System . out . println ( " Entrer l ID : " );
String id = null ;
id = br . readLine ();
int idToDelete = Integer . parseInt ( id );
boolean isDelete =
myAdministrator . delete ( idToDelete );
if ( isDelete ){
System . out . println ( " Suppression "
+ " reussie ... " );
}

20

CHAPITRE 9. PREMIERS PAS J2EE

else {
System . out . println ( " Supression "
+ " echouee ... " );
}

108

}
else if ( secondaryChoice . equals ( " 3 " )){
myAdministrator . logout ();
isLog = false ;
System . out . println ( " Logout ... " );
}
else {
System . out . println ( " Choix incorrect ... " );
}

113

118

}
}
else {
System . out . println ( " Username ou Password "
+ " incorrect ... " );
}

123

}
else {
System . out . println ( " Choix incorrect ... " );
}

128

}
} catch ( Exception e ) {
System . err . println ( " Erreur : " + e );
System . exit (2);
}

133

}
}

Listing 9.17 Fichier AdministratorClient.java

9.3.4

Compilation du bean et du client, d


eploiement du bean et
ex
ecution du client

Il est essentiel que le repertoire du session bean connaisse les interfaces de lentity
bean quil va acceder. Il est donc necessaire de copier les interfaces home et remote de
lentity bean (CarteDeVisiteCMPHome.java et CarteDeVisiteCMP.java) dans le repertoire
src du session bean avec lensemble du package2 .
Il reste aussi `
a copier le script associe `a lentity bean (manage.sh) dans le repertoire
du session bean et de le mettre `
a jour avec les modifications suivantes :
JAR_NAME = Administrator . jar
CLIE NT_CLASS_NAME = administrators . AdministratorClient

Lexecution du client doit etre parametree de la mani`ere suivante :

jclient - cp / opt / JONAS_4_7_7 / ejbjars / $JAR_NAME :\


$JONAS_ROOT / ejbjars / CarteDeVisiteCMP . jar \
- argclient $CLIENT_CLASS_NAME
2

Une solution plus eleguante, laisxssee au lecteur en exercice, serait dimplementer un syst`eme de chargement de classe dynamique qui telechargerait ces classes depuis le serveur Jonas a
` lexecution.


9.3. LA PARTIE METIER
- STATEFULL SESSION BEAN

21

Il ne reste plus qu`


a utiliser le script pour compiler le bean et le client, deployer le bean
puis execution le client.
2

12

17

22

27

32

37

42

47

52

LINUX :~/ Administrator > ./ manage . sh compile


# # src --> bin compilation
# # Deploying xml descriptors
# # Building Administrator . jar
LINUX :~/ Administrator >
LINUX :~/ Administrator > ./ manage . sh load
# # Moving Administrator . jar --> / opt / JONAS_4_7_7 / ejbjars
# # Loading Administrator . jar in JONAS
LINUX :~/ Administrator > ./ manage . sh run
# # Runnning client ...
ClientContainer . info : Starting client ...
1. Connexion
2. Quitter
>
toto
Choix incorrect ...
1. Connexion
2. Quitter
>
1
Username :
toto
Password :
titi
Username ou Password incorrect ...
1. Connexion
2. Quitter
>
1
Username :
admin
Password :
admin
1. Ajouter une carte de visite
2. Retirer une carte de visite
3. Se deconnecter
>
1
Ajout d une carte de visite ...
Entrer le nom :
MOSSER
Entrer le prenom :
sebastien
Entrer le mail :
mosser@polytech . unice . fr
Entrer le numero de tel :
01234566
Ajout reussi ...
1. Ajouter une carte de visite
2. Retirer une carte de visite
3. Se deconnecter
>
1

22

57

62

67

72

CHAPITRE 9. PREMIERS PAS J2EE

Ajout d une carte de visite ...


Entrer le nom :
JOFFROY
Entrer le prenom :
Cedric
Entrer le mail :
joffroy@polytech . unice . fr
Entrer le numero de tel :
987654321
Ajout reussi ...
1. Ajouter une carte de visite
2. Retirer une carte de visite
3. Se deconnecter
>
3
Logout ...
1. Connexion
2. Quitter
>
2
Bye bye ...

9.4

La partie m
etier (suite) - stateless session bean

Apr`es avoir ecrit la partie metier qui sera utilise par ladministrateur de lapplication,
nous allons construire celle utilisee par tous les utilisateurs souhaitant consulter la base de
cartes de visite. La consultation dune carte ne necessite pas de session, nous utiliserons
donc un stateless session bean.
Comme tout bean, un stateless session bean a une remote interface, une home interface,
une implementation et deux descripteurs.

9.4.1

Ecriture du stateless session bean

Remote interface
1

package consultators ;
import javax . ejb . EJBObject ;
import java . rmi . RemoteException ;

import java . util .*;


public interface Consultator extends EJBObject {
// Find a card looking on name
public Collection rechercherNom ( String nom )
throws RemoteException ;

11

// Find a card with a prefix


public Collection rechercherPrefix ( String prefix )
throws RemoteException ;

16


9.4. LA PARTIE METIER
(SUITE) - STATELESS SESSION BEAN

Listing 9.18 Fichier Consultator.java

Home interface
package consultators ;
3

import java . rmi . RemoteException ;


import javax . ejb . CreateException ;
import javax . ejb . EJBHome ;
public interface ConsultatorHome extends EJBHome {

Consultator create () throws RemoteException , CreateException ;


}

Listing 9.19 Fichier ConsultatorHome.java

Impl
ementation du bean
package consultators ;

import java . rmi . RemoteException ;


import javax . ejb . SessionBean ;
import javax . ejb . SessionContext ;
import javax . rmi .*;
import javax . naming . InitialContext ;
import javax . naming . Context ;
import java . util .*;
import carte_cmp .*;

14

public class ConsultatorBean implements SessionBean {

19

24

public Collection rechercherNom ( String nom ) {


try {
Context initialContext = new InitialContext ();
Object objref = initialContext . lookup ( " MyCarteDeVisiteCMP " );
// Reference a l interface locale de l EJB
CarteDeVisiteCMPHome home = ( CarteDeVisiteCMPHome )
PortableRemoteObject . narrow ( objref ,
CarteDeVisiteCMPHome . class );
// Objet de type client pour faire nos tests
CarteDeVisiteCMP test ;

29

// Recherche par le nom de la personne


Collection c1 = home . findByNom ( nom );

23

24

CHAPITRE 9. PREMIERS PAS J2EE

return c1 ;
}
catch ( Exception e ) {
System . err . println ( " Erreur : " + e );
}
return null ;

34

39

44

public Collection rechercherPrefix ( String prefix ) {


try {
Context initialContext = new InitialContext ();
Object objref = initialContext . lookup ( " MyCarteDeVisiteCMP " );

49

// Reference a l interface locale de l EJB


CarteDeVisiteCMPHome home = ( CarteDeVisiteCMPHome )
PortableRemoteObject . narrow ( objref ,
CarteDeVisiteCMPHome . class );
// Objet de type client pour faire nos tests
CarteDeVisiteCMP test ;
// Recherche par le prefix de la personne
Collection c1 = home . findByPrefix ( prefix );

54

return c1 ;
}
catch ( Exception e ) {
System . err . println ( " Erreur : " + e );
}
return null ;

59

}
64

public
public
public
public
public

69

void
void
void
void
void

ejbCreate () {}
ejbRemove () {}
ejbActivate () {}
ejbPassivate () {}
setSessionContext ( SessionContext sc ) {}

Listing 9.20 Fichier ConsultatorBean.java


Descripteur J2EE

10

<? xml version ="1.0" encoding =" ISO -8859 -1"? >
<ejb - jar >
< description > Descripteur de deploiement du consultator </ description >
< display - name > Consultator </ display - name >
< enterprise - beans >
< session >
< description > Consultator </ description >
< display - name > Consultator </ display - name >
<ejb - name > Consultator </ ejb - name >
< home > consultators . ConsultatorHome </ home >
< remote > consultators . Consultator </ remote >


9.4. LA PARTIE METIER
(SUITE) - STATELESS SESSION BEAN

15

20

25

<ejb - class > consultators . ConsultatorBean </ ejb - class >


< session - type > Stateless </ session - type >
< transaction - type > Container </ transaction - type >
</ session >
</ enterprise - beans >
< assembly - descriptor >
< container - transaction >
< method >
<ejb - name > Consultator </ ejb - name >
< method - name >* </ method - name >
</ method >
< trans - attribute > Required </ trans - attribute >
</ container - transaction >
</ assembly - descriptor >
</ ejb - jar >

Listing 9.21 Fichier ejb-jar.xml

Descripteur Jonas

<? xml version ="1.0" encoding =" ISO -8859 -1"? >
< jonas - ejb - jar >
< jonas - session >
<ejb - name > Consultator </ ejb - name >
< jndi - name > MyConsultator </ jndi - name >
</ jonas - session >
</ jonas - ejb - jar >

Listing 9.22 Fichier jonas-ejb-jar.xml

9.4.2

Client dun session bean

Nous commencons `
a etre rode... aucune difficulte particuli`ere.
package consultators ;
3

import
import
import
import

java . util . Properties ;


javax . naming . InitialContext ;
javax . naming . Context ;
javax . rmi . PortableRemoteObject ;

import
import
import
import
import

java . io . BufferedReader ;
java . io . InputStreamReader ;
java . io . IOException ;
java . io . OutputStreamWriter ;
java . io . PrintWriter ;

13

import java . util .*;


import carte_cmp .*;
public class ConsultatorClient {
18

public static void main ( String args []) {

25

26

CHAPITRE 9. PREMIERS PAS J2EE

try {
23

28

33

// Recherche de l interface home de l EJB


Context initialContext = new InitialContext ();
Object objref = initialContext . lookup ( " MyConsultator " );
// Reference a l EJB
ConsultatorHome home = ( ConsultatorHome )
PortableRemoteObject . narrow ( objref , ConsultatorHome . class );
Consultator myConsultator = home . create ();
// On va chercher des gens
InputStreamReader isr = new InputStreamReader ( System . in );
BufferedReader br = new BufferedReader ( isr );
boolean isQuit = false ;

38

while ( isQuit == false ){


System . out . println ( " 1. Rechercher par nom " );
System . out . println ( " 2. Rechercher par prefixe ( sur le nom ) " );
System . out . println ( " 3. Quitter " );
System . out . println ( " >" );

43

48

53

58

63

68

73

String choice = null ;


choice = br . readLine ();
if ( choice . equals ( " 1 " )){
System . out . println ( " Recherche par nom ... " );
String nom = null ;
System . out . println ( " Entrez le nom : " );
nom = br . readLine ();
CarteDeVisiteCMP test = null ;
Collection cl = myConsultator . rechercherNom ( nom );
System . out . println ( " recherche sur le nom : " + nom );
if ( cl != null ){
Iterator iLast = cl . iterator ();
while ( iLast . hasNext ()) {
test = iLast . next ();
System . out . println ( " ->" + test . getPrenom ());
}
}
else {
System . out . println ( " Echec de recherche ... " );
}
}
else if ( choice . equals ( " 2 " )){
System . out . println ( " Recherche par prefixe ... " );
String prefix = null ;
System . out . println ( " Entrez le prefixe : " );
prefix = br . readLine ();
CarteDeVisiteCMP test = null ;
Collection c2 = myConsultator . rechercherPrefix ( prefix );
System . out . println ( " recherche sur le prefix : " + prefix );
if ( c2 != null ){
Iterator iLast2 = c2 . iterator ();
while ( iLast2 . hasNext ()) {
test = iLast2 . next ();


9.4. LA PARTIE METIER
(SUITE) - STATELESS SESSION BEAN

System . out . println ( " ->" + test . getPrenom ());


}

78

}
else {
System . out . println ( " Echec de recherche ... " );
}
}
else if ( choice . equals ( " 3 " )){
System . out . println ( " Bye bye ... " );
isQuit = true ;
}
else {
System . out . println ( " Choix incorrect ... " );
}

83

88

}
} catch ( Exception e ) {
System . err . println ( " Erreur : " + e );
System . exit (2);
}

93

}
}

Listing 9.23 Fichier ConsultatorClient.java

9.4.3

Compilation, d
eploiement et ex
ecution

A vous de jouer. Voici un exemple dexecution :

13

18

23

LINUX :~/ Consultator > ./ manage . sh run


# # Runnning client ...
ClientContainer . info : Starting client ...
1. Rechercher par nom
2. Rechercher par prefixe ( sur le nom )
3. Quitter
>
1
Recherche par nom ...
Entrez le nom :
mosser
recherche sur le nom : mosser
-> sebastien
1. Rechercher par nom
2. Rechercher par prefixe ( sur le nom )
3. Quitter
>
2
Recherche par prefixe ...
Entrez le prefixe :
m
recherche sur le prefix : m
-> sebastien
1. Rechercher par nom
2. Rechercher par prefixe ( sur le nom )
3. Quitter
>

27

28

28

CHAPITRE 9. PREMIERS PAS J2EE

3
Bye bye ...

9.5

La partie pr
esentation - servlet

9.5.1

Principe

Apr`es avoir construit plusieurs clients lourds, il nous semble essentiel de pouvoir offrir
aux utilisateurs eventuels la possibilite de consulter les cartes depuis un client leger.
Dans lapproche J2EE, les clients legers sont offerts par exemple par lutilisation de
servlet qui gen`erent des pages html consultables depuis nimporte quel butineur web.

9.5.2

Ecriture de la servlet

Les differents repertoires utilises sont :


src : contient les sources de la servlet
bin/WEB-INF/ : contient les descripteurs de deploiements
bin/WEB-INF/classes : le code compile de la servlet.
La servlet implementee reagira a` une requete GET3 et son code est le suivant :
1

11

import
import
import
import
import
import
import
import
import
import
import
import

java . io . PrintWriter ;
java . io . IOException ;
java . util . Collection ;
java . util . Iterator ;
javax . servlet . ServletException ;
javax . servlet . http . HttpServlet ;
javax . servlet . http . HttpServletRequest ;
javax . servlet . http . HttpServletResponse ;
javax . servlet . http . HttpSession ;
javax . naming . Context ;
javax . naming . InitialContext ;
javax . rmi . PortableRemoteObject ;

import consultators .*;


import carte_cmp .*;
16

public class Consult extends HttpServlet {


protected void doGet ( HttpServletRequest req , HttpServletResponse res )
throws ServletException , IOException {
res . setContentType ( " text / html " );
PrintWriter out = res . getWriter ();
head ( out );
Object prefix = req . getParameter ( " prefix " );
look ( prefix , out );
foot ( out );
}

21

26

private void look ( Object p , PrintWriter out ) {


3

Il est possible de construire une servlet reagissant a


` une requete POST

methode doPost.

en implementant une


9.5. LA PARTIE PRESENTATION
- SERVLET

31

36

41

46

51

56

61

66

71

if ( p == null ) {
out . println ( " You must enter a name ! " );
return ;
}
String prefix = ( String ) p ;
if ( prefix . equals ( " " )) {
out . println ( " You must enter a name ! " );
return ;
}
// Initializing context
Context initialContext = null ;
try {
initialContext = new InitialContext ();
}
catch ( Exception e ) {
out . println ( " <h3 > Unable to find InitialContext ! </ h3 > " );
out . println ( e + " < br / > " );
return ;
}
// Connecting to the bean
ConsultatorHome home = null ;
try {
home = ( ConsultatorHome )
PortableRemoteObject . narrow (
initialContext . lookup ( " MyConsultator " ) ,
ConsultatorHome . class );
}
catch ( Exception e ) {
out . println ( " <h3 > Unable to retrieve MyConsultator ! </ h3 > " );
out . println ( e + " < br / > " );
return ;
}
// Instanciation
Consultator consult = null ;
try {
consult = home . create ();
}
catch ( Exception e ) {
out . println ( " <h3 > Unable to create a Consultator "
+ " instance ! </ h3 > " );
out . println ( e + " < br / > " );
return ;
}

76

81

// Doing the search ...


Collection result = null ;;
try {
result = consult . rechercherPrefix ( prefix );
out . println ( " <h2 > Search Result for " + prefix + " </ h2 > " );
printResult ( result , out );
}
catch ( Exception e ) {
out . println ( " <h3 > Unable to invoke the Consultator ! </ h3 > " );

29

30

CHAPITRE 9. PREMIERS PAS J2EE

out . println ( e + " < br / > " );


return ;

86

91

private void printResult ( Collection c , PrintWriter out )


throws Exception {
if ( c . size () == 0) {
out . println ( " < strong > No match found ! </ strong > " );
}
Iterator i = c . iterator ();
while ( i . hasNext ()) {
CarteDeVisiteCMP card = ( CarteDeVisiteCMP ) i . next ();
out . println ( " <h4 > " + card . getNom () + " " + card . getPrenom ()
+ " </ h4 > " );
out . println ( " <ul > " );
out . println ( " <li > Telephone : " + card . getPhone () + " </ li > " );
out . println ( " <li > Email : " + card . getEmail () + " </ li > " );
out . println ( " </ ul > " );
}

96

101

106

}
111

private void head ( PrintWriter out ) {


out . println ( " < html > < head > < title > Card Consultation Form </ title > "
+ " </ head > " );
out . println ( " < body > " );
out . println ( " <h1 > Looking for Someone ? </ h1 > < br > " );
out . println ( " < form method =\" get \" > " );
out . println ( " <p > " );
out . println ( " Name : & nbsp ; "
+ " < input type =\" text \" name =\" prefix \" / > " );
out . println ( " < br / > < input type =\" submit \" value =\" Search !\"/ > " );
out . println ( " </p > " );
out . println ( " </ form > " );
}

116

121

private void foot ( PrintWriter out ) {


out . println ( " </ body > " );
out . println ( " </ html > " );
out . close ();
}

126

131

Listing 9.24 Fichier Consult.java

Descripteur J2EE
Le descripteur permet de decrire lURL associee `a la servlet ainsi que les liens avec les
beans utilises.
<? xml version ="1.0" encoding =" ISO -8859 -1"? >


9.5. LA PARTIE PRESENTATION
- SERVLET

14

19

31

<web - app xmlns =" http :// java . sun . com / xml / ns / j2ee "
xmlns : xsi =" http :// www . w3 . org /2001/ XMLSchema - instance "
xsi : schemaLocation =" http :// java . sun . com / xml / ns / j2ee
http :// java . sun . com / xml / ns / j2ee / web - app_2_4 . xsd "
version ="2.4" >
< servlet >
< servlet - name > CardManager </ servlet - name >
< servlet - class > Consult </ servlet - class >
</ servlet >
< servlet - mapping >
< servlet - name > CardManager </ servlet - name >
<url - pattern >/ card / consult </ url - pattern >
</ servlet - mapping >
<ejb - ref >
<ejb - ref - name > Consultator </ ejb - ref - name >
<ejb - ref - type > Session </ ejb - ref - type >
< home > consultators . ConsultatorHome </ home >
< remote > consultators . Consultator </ remote >
<ejb - link > Consultator . jar </ ejb - link >
</ ejb - ref >
</ web - app >

Listing 9.25 Fichier web.xml

Descripteur Jonas
Ce descripteur decrit les liens avec le session bean utilise.

<? xml version ="1.0" encoding =" ISO -8859 -1"? >
< jonas - web - app xmlns =" http :// www . objectweb . org / jonas / ns "
xmlns : xsi =" http :// www . w3 . org /2001/ XMLSchema - instance "
xsi : schemaLocation =" http :// www . objectweb . org / jonas / ns
http :// www . objectweb . org / jonas / ns / jonas - web - app_4_0 . xsd " >
< jonas - ejb - ref >
<ejb - ref - name > Consultator </ ejb - ref - name >
< jndi - name > MyConsultator </ jndi - name >
</ jonas - ejb - ref >
< host > localhost </ host >
< context - root > web - application </ context - root >
</ jonas - web - app >

Listing 9.26 Fichier jonas-web.xml

9.5.3

Compilation et d
eploiement

Les servlets sont chargees comme des applications web, et doivent etre packagees comme
telles. Ainsi, on archivera le contenu du repertoire bin dans un fichier war (pour Web
Archive) et non dans un jar (Java Archive)4 .
4

Un fichier .war

se gen`ere comme un fichier .jar en utilisant la commande jar

32

CHAPITRE 9. PREMIERS PAS J2EE

Compilation
La servlet acc`ede au session bean et entity bean via son interface remote quil faut
donc copier dans le repertoire src.
TODO pourquoi aussi lentity bean ?
TODO pourquoi pas via un proxy ?

LINUX :~ > javac - cp $JONAS \ _ROOT / lib / commons / j2ee . servlet . jar -d bin / WEB - INF / classes src /* ja
LINUX :~ > cp web . xml jonas - web . xml bin / WEB - INF /.
LINUX :~ > cd bin
LINUX :~/ bin > jar cf ../ Consult . war *
LINUX :~/ bin > cd ..

Chargement
LINUX :~ > mv Consult . war > JONAS_ROOT / webapps /.
LINUX :~ > cd $JONAS_ROOT / webapps
LINUX :~ > jonas admin -a Consult . war

Ex
ecution
Il suffit douvrir son butineur prefere, et de se rendre `a ladresse decrite dans le fichier
de mapping : http://localhost:9000/web-application/card/consult.

9.6

Pour aller plus loin

Ecrire une servlet pour ladministration de lannuaire.


Utiliser la securite J2EE
Utiliser les transactions