|
EJB 2 - Les Entreprise Java Bean (JavaBeans)
4.6.La vue cliente
Le client d’un EJB ne travaille pas directement avec le système
EJB. En outre, le client accède via des interfaces à
des beans et leur logique métier. Ces interfaces regroupent
l’API JNDI (Java Naming Directory Interface) et une API client
EJB.
Pendant que JNDI est utilisé pour localiser et accéder
aux EJB de façon transparente, l’API client EJB est un
ensemble d’interfaces et classes que le développeur
utilise pour travailler avec les beans.
Nous verrons dans ce chapitre plusieurs petits exemples de code
permettant de localiser / accéder / travailler avec les beans.
Vous trouverez un code complet dans le chapitre : EJB par la
pratique.
4.6.1.Localisation de Beans avec
JNDI
Une application cliente commence toujours par localiser les EJB que
l’on souhaite utiliser. La classe InitialContext (que vous
retrouverez dans les exemples) fait partie de l’API JNDI. Nous
utilisons celle-ci pour pour chercher un objet : « EJB
Home » sur un serveur d’EJB comme vous pourriez
utiliser un carnet d’adresse pour retrouver le téléphone
d’un ami.
JNDI est un standard en java. Il permet donc d’uniformiser la
connexion à un service d’annuaire, comme le fait JDBC
pour les bases de données. Il existe différent
fournisseurs d’annuraire, chacun d’eux doit donc fournir
son propre driver pour son type d’annuaire (LDAP, Système
de fichier, EJB …).
Une fois que le client a pu récupérer un objet de type
« EJB Home » grâce à JNDI,
celui-ci peut l’utiliser pour obtenir une objet de référence
vers l’EJB.
Le context initial doit être configuré suivant le
serveur d’application, voici un exemple d’utilisation
avec le serveur JBoss :
/**
* Get the initial naming context
*/
protected
Context getInitialContext() throws Exception {
Hashtable
props = new Hashtable();
props.put(
Context.INITIAL_CONTEXT_FACTORY,
"org.jnp.interfaces.NamingContextFactory");
props.put(
Context.URL_PKG_PREFIXES,
"org.jboss.naming:org.jnp.interfaces");
props.put(Context.PROVIDER_URL,
"jnp://localhost:1099");
Context
ctx = new InitialContext(props);
return
ctx;
}
Nous pouvons remarquer que le driver est la classe :
org.jnp.interfaces.NamingContextFactory. Il faudra donc que cette
classe soit dans le classpath du client.
4.6.2.L’api Client distant
Un EJB est constitué de sa classe d’implémentation
(Bean), de ses interfaces, de sa classe de clé primaire (si
spéciale) et d’autres classes dites « Helper ».
Parrallèlement, le client n’a besoin que des interfaces
et de la classe de clé primaire et des classes helper. Cet
ensemble contribue donc à l’API Cliente. API qui
permettra au client d’intéragir avec le système
métier EJB.
Depuis la spécification 2.0, les ejb peuvent définir
des interfaces locales et donc faciliter la connexion entre les EJB
locaux.
Nous détaillerons principalement l’API Distance client
car c’est la plus complexe (couche réseau …).
4.6.3.RMI – IIOP
La communication entre le serveur d’EJB et le client distant se
fait via RMI et plus particulièrement par le protocole
RMI-IIOP. Ce protocole étant compatible avec CORBA, cela
permet d’être beaucoup plus portable qu’un
protocole propriétaire.
Cependant, les types et valeurs utilisés dans les interfaces
doivent être compatibles avec le protocole.
Nous allons voir plus en détail, les différentes faces
de ce protocole. Bien entendu, ces restrictions s’appliquent
uniquement aux accès distants, les accès locaux
n’utilisant pas RMI…
Les interfaces remote home interface et remote interface héritent
respectivement de EJBHome et EJBObject, qui héritent également
de java.rmi.Remote. Elles doivent donc respecter les spécifications
RMI :
-
Types de retour et paramètres doivent être :
-
Primitives
-
String
-
java.rmi.Remote objets
-
java.io.Serializable objets
Vous avez peut-être remarqué que l’ensemble des
méthodes d’une Remote interface doit pouvoir jeter des
exceptions du type : java.rmi.RemoteException. Ce type
d’exception est utilisé lorsque l’application
rencontre des problèmes avec la distribution d’objets de
communication par exemple :
-
une coupure de réseau
-
impossiblité de trouver le serveur
-
…
PortableRemoteObject
Dans l’API Java RMI-IIOP les références distantes
doivent être « narrowed » en utilisant la
méthode : PortableRemoteObject.narrow().
En effet, la méthode lookup de l’objet Context, renvoie
un « Object ». Comme les clients distants
utilisent l’API RMI-IIOP, ils sont donc restreints à
respecter le protocole IIOP 1.2.
Certains langages ne prennent pas en compte le concept de
« casting », le protocole IIOP ne supporte donc
pas l’implémentation de multiples interfaces. Les
« stub » retrournés avec IIOP implémente
seulement une interface spécifiée par le type de retour
de la méthode retournant l’objet distant.
Si le type de retour est : « Object »
comme c’est le cas pour la méthode lookup(),
les stub implémenteront seulement le type Object.
Cependant, il n’est pas intéressant de récupérer
un objet si son type est Object (vous ne pourrez rien en faire). De
ce fait, Java RMI fournit un mécanisme pour explicitement
« narrowed » vers un type particulier. Pour
cela, vous devez utiliser la méthode narrow de l’objet
PortableRemoteObject.
/**
*
Get the home interface
*/
protected
com.society.stockmanager.interfaces.StorageServiceHome getHome()
throws Exception {
Context
ctx = this.getInitialContext();
Object
o = ctx.lookup("ejb/StorageService");
com.society.stockmanager.interfaces.StorageServiceHome
intf = (com.society.stockmanager.interfaces.StorageServiceHome)
PortableRemoteObject
.narrow(o,
com.society.stockmanager.interfaces.StorageServiceHome.class);
return
intf;
}
Cas d’utilisation :
-
Lorsque vous récupérer la home interface EBJ via la
méthode lookup
Object
ref = jndiContext.lookup("ejb/Product");
CabinHomeRemote
home = (ProductHome) // remote home
PortableRemoteObject.narrow(ref,
ProductHome.class);
-
Lorsque vous appelez la méthode :
javax.ejb.Handle.getEJBObject()
Handle
handle = .... // get handle
Object
ref = handle.getEJBObject();
Product
prod = (Product) // remote interface
PortableRemoteObject.narrow(ref,
Product.class);
-
Lorsque vous appelez la méthode :
javax.ejb.HomeHandle.getEJBHome()
HomeHandle
homeHdle = ... // get home handle
EJBHome
ref = homeHdle.getEJBHome();
ProductHome
home = (ProdcutHome) // home interface
PortableRemoteObject.narrow(ref,
ProductHome.class);
-
Lorsque vous récupérez une référence à
un EJB distant depuis une collection
ProductHome
productHome = ... // get product home
Enumeration
enum = productHome.findByQuantity(2000);
while(enum.hasMoreElements()){
Object
ref = enum.nextElement();
Product
product = (Product) // remote interface
PortableRemoteObject.narrow(ref,
Product.class);
//
do something with product reference
}
4.6.4.Remote Home Interface
La remote home interface fournit l’ensemble des opérations
liées au cycle de vie d’un bean, mais également
les opérations d’acquisions des informations de
méta-données. Lorsque vous utilisez JNDI vous récupérer
une référence distance vers l’interface home de
l’EJB. Celle-ci implémente l’interface
javax.ejb.EJBHome :
public
interface javax.ejb.EJBHome extends java.rmi.Remote {
public
abstract EJBMetaData getEJBMetaData()
throws
RemoteException;
public
HomeHandle getHomeHandle() // new in 1.1
throws
RemoteException;
public
abstract void remove(Handle handle)
throws
RemoteException, RemoveException;
public
abstract void remove(Object primaryKey)
throws
RemoteException, RemoveException;
}
Vous pouvez ensuite utiliser votre objet pour gérer la vie de
l’EJB distant lié (création, suppression …)
Remove
La méthode remove de l’interface EJBHome est responsable
de la suppression d’un EJB. Elle prend en argument, soit
l’objet Handle, soit la clé primaire (dans le cas d’un
entity bean).
Dès que le client appelle cette méthode, la référence
à l’EJB devient invalide.Si un problème survient
lors de la suppression, une exception de type : RemoveException
est lancée.
La suppression diffère suivant le type d’EJB.
Si vous supprimez un session bean, c’est la session du service
qui est arrêtée. L’état de conversation est
supprimé et toutes les informations liées à
cette session.
Dans le cas d’un entity bean, la suppression annule la
référence entre le client et le serveur, mais enlève
également toutes les données liées au bean de la
base de données. L’action de suppression sur un entity
bean est donc plus importante que sur un session bean.
BeanMetaData
La méthode getEJBMetaData() de l’interface
EJBHome retourne une instance de type : javax.ejb.EJBMetaData
qui décrit la remote home interface, la remote interface, a
clé primaire, et le type d’EJB (session ou entity).
Cette « fonctionnalité » trouve un grand
intérêt dans les IDE de développement. En effet,
vous pouvez créer un client simplement en vous connectant sur
l’ejb distant et en récupérant les différentes
informations. Vous pouvez retrouver le nom de l’interface home,
interface remote …
Voici le prototype de cette interface :
public
interface javax.ejb.EJBMetaData {
public
abstract EJBHome getEJBHome();
public
abstract Class getHomeInterfaceClass();
public
abstract Class getPrimaryKeyClass();
public
abstract Class getRemoteInterfaceClass();
public
abstract boolean isSession();
}
Vous pouvez remarquer qu’en utilisant la réflexion en
Java, vous pouvez retrouver l’ensemble des informations liées
aux interfaces (méthodes, paramètres …).
Voici un exemple d’utilisation de cette interface :
Context
jndiContext = getInitialContext();
Object
ref = jndiContext.lookup("ejb/Product");
ProductHome
c_home = (ProductHome)
PortableRemoteObject.narrow(ref,
ProductHome.class);
EJBMetaData
meta = c_home.getEJBMetaData();
System.out.println(meta.getHomeInterfaceClass().getName());
System.out.println(meta.getRemoteInterfaceClass().getName());
System.out.println(meta.getPrimaryKeyClass().getName());
System.out.println(meta.isSession());
Home Handle
L’API EJB fournit un objet appelé un « HomeHandle »
que l’on peut récupérer en appelant la méthode :
getHomeHandle() de l’interface EJBHome.
Cette méthode retourne un objet de type :
javax.ejb.HomeHandle qui correspond à un objet sérialisable
qui référence une remote home interface. Cet objet
HomeHandle permet d’enregistrer une référence à
une remote home interface afin d’être utilisée
plus tard.
4.6.5.Remote Interface
L’interface « Remote » se focalise sur
les problèmes liés au métier (business). Vous ne
devez pas inclure de méthodes liées aux opérations
systèmes tel la persistance, la securité … (qui
sont gérés par le conteneur).
Chacune des méthodes doit renvoyer au moins des
java.rmi.RemoteException. Cette exception permet d’indiquer au
client un problème dû au réseau (communication
…).
EJBObject
L’interface Remote doit hériter de :
javax.ejb.EJBObject (qui hérite de java.rmi.Remote).
Voici la définition de cette interface :
public
interface javax.ejb.EJBObject extends java.rmi.Remote {
public
abstract EJBHome getEJBHome()
throws
RemoteException;
public
abstract Handle getHandle()
throws
RemoteException;
public
abstract Object getPrimaryKey()
throws
RemoteException;
public
abstract boolean isIdentical(EJBObject obj)
throws
RemoteException;
public
abstract void remove()
throws
RemoteException, RemoveException;
}
Lorsque que le client obtient une référence à
une remote interface, il obtient, en réalité, une
référence distante à un objet EJB. Cet objet
implémente la remote interface et délègue
l’ensemble des méthodes métiers à la
classe du bean, il implémente donc de sa propre façon
les méthodes de l’interface EJBObject.
Bien entendu cette implémentation est automatiquement gérée
par le conteneur et est générée lors du
déploiement.
Handle
La méthode getHandle() de l’interface
EJBObject retourne un objet de type : javax.ejb.Handle.
C’est une référence, à l’objet EJB
distant, sérialisable. Cela permet de sérialiser le
handle et le déserialiser afin de se reconnecter à
l’EJB plus tard.
Cette interface ne définit qu’une seule méthode :
public
interface javax.ejb.Handle {
public
abstract EJBObject getEJBObject()
throws
RemoteException;
}
La méthode getEJBObject() retourne l’objet
EJB distant à partir duquel le « handle »
avait été créé. Vous devrez bien entendu
utiliser la méthode « PortableRemoteObject.narrow() »
vu que la méthode retourne un objet typé sur
l’interface « Handle ».
Cette fonectionnalité est très pratique, car elle vous
permet de ne faire qu’un seul appel à la méthode
getEJBObject() pour récupérer votre EJB
distant. Si vous passez par la méthode « classique »
vous devez le faire en 3 étapes (« lookup JNDI »,
« récupérer la home interface »,
« récupérer l’objet ejb distant).
Clé primaire
Vous pouvez récupérer la clé primaire d’un
entity bean via la méthode getPrimaryKey().
Cette clé primaire est très utile, car elle vous
permettra de récupérer votre objet entity via la
méthode findByPrimaryKey().
Une clé primaire doit impérativement implémenter
java.io.Serializable. En effet, elle est enregistrée en
tant que données dans la base.
Vous pouvez également vous en servir du côté
client. En effet, si le client connaît la clé d’un
EJB entity, alors il peut le récupérer (via le
findByPrimaryKey). Cette clé étant
sérialisable, le client peut l’enregistrer dans un
fichier (en local) et s’en reservir plus tard.
Remove
La méthode remove de l’interface EJBObject est
utilisée pour supprimer un session ou entity bean. Cette
méthode effectue le même traitement que la méthode
remove de l’interface EJBHome. Pour les sessions
beans, cette méthode supprime toutes références
à l’EJB distant, qui devient inaccessible pour le
client. Pour un entity bean, l’entité liée à
l’objet EJBObject est supprimée de la base de
données et devient donc invalide pour le client.
Cette méthode peut jeter des « RemoveException »
si la suppression s’est mal passée.
|
|
 |