Cours assuré par Olivier Caron (support de cours).
Intervenant en Travaux Pratiques et en tutorat Projet
Dans le monde Java, on parle de communications à distance dès lors qu'un objet d'une machine virtuelle (JVM) échange des données avec un objet d'une autre JVM, même si celle-ci est exécutée sur la même machine : ce sont 2 processus différents qui ne peuvent dialoguer que via la couche réseau.
Pour masquer la complexité de la couche réseau, les frameworks sont capables de générer des objets : stub (rôle client) et skeleton (rôle serveur), de manière transparente pour l'utilisateur, qui permettent de manipuler des objets distants tout en ayant l'impression que ce sont des objets locaux.
Comme un objet A côté client ne peut pas pas dialoguer avec un objet B côté serveur, nous devons utiliser une librairie d'accès à distance. Il en existe plusieurs, fonctionnant sur le même principe mais différent par le protocole utilisé (IIOP, HTTP, etc.). Quand l'objet B (rôle serveur) sera instancié, un squelette (skeleton) sera instantié en même temps afin de gérer la couche réseau et être à l'écoute des requêtes entrantes. Quand le client voudra dialoguer avec l'objet B, il ne va pas instantier un objet B (dans ce cas, nous aurions 2 objets B différents : un côté serveur et un côté client) mais va demander à la librairie de créer un objet de type B (ou en récupérer un enregistré dans un annuaire) à notre place. La librairie va alors créer un objet stub lié à l'objet distant B dans la machine virtuelle du client. L'objet retourné n'est pas de type B mais du type de l'interface de B (MyServiceInterface): la librairie a construit une sorte de proxy ayant le même comportement que l'objet B (mêmes méthodes) et permettant de dialoguer avec lui en cachant la complexité de la couche réseau.
Les communications entre client et serveur:
Les JSP sont une technologie permettant d'ajouter du contenu dynamique à des pages Webs en s'appuyant sur Java. Ils offrent un confort au programmeur en permettant de mixer du code Java (à l'aide de balises JSP) et du code HTML. Les JSP, avant de pouvoir être utilisées, sont transformées en Servlet Java. Le code HTML est encapsulé dans des instructions out.write(""), les déclarations de méthodes et d'attributs deviennent membres de la classe générée, et le code entre balises <% et %> se retrouve dans la méthode _jspService(). Cette méthode est appelée lorsque le browser fait une requête au JSP.
application.xml : décrit une application J2EE, notamment les modules (web, ejb) la composant. La balise context-root désigne l'url à laquelle sera accessible notre application. Cette url est relative à l'url de déploiement du serveur d'applications (ex: http://localhost:8080).
Afin de pouvoir dialoguer avec la base de données dans un EJB Entité, vous devez déclarer une instance de gestionnaire d'entité :
Celui-ci est associé à un contexte de persitance déclaré dans le descripteur persistence.xml
Le lien se fait grâce au nom de l'unité de persistance (unit-name). Le lien avec la base de données se fait, quant à lui, grâce à la source de données (jta-data-source) déclarée dans l'unité de persistance (toujours dans persistence.xml). Cette source de données a été déclarée au niveau du serveur d'application en précisant l'adresse de la base de données, l'utilisateur et le mot de passe à utiliser pour s'y connecter.
La convention de nommage veut que les accesseurs utilisent les noms de rôle des associations.
L'association peut être bidirectionnelle. Dans une relation bidirectionnelle, une des extrémités (et seulement une) doit être la propriétaire : la propriétaire est responsable de la mise à jour des colonnes de l'association. Cela signifie que pour persister les données en base, il faut obligatoirement utiliser le setter du propriétaire de l'association.
Pour déclarer une extrémité comme non responsable de la relation, l'attribut mappedBy est utilisé. mappedBy référence le nom de la propriété de l'association du côté du propriétaire. Dans l'exemple ci-dessous, A est propriétaire de l'association.
Pour mettre à jour les données, il faut donc procéder comme suit:
La mise à jour des données via anInstanceOfB ne provoquera pas d'erreur mais les données ne seront pas persistées en base.
Si, lorsque vous tentez de récupérer une référence vers un EJB session distant, une exception NoSuchEJBException est lancée, vérifiez:
Pour un accès local, on utilisera une adresse commançant par java:. Pour un accès distant, il faut utiliser une adresse commançant par ejb:.
La persistance des EJB entités est assurée par l'EntityManager. L'Entity manager sait comment persister les données en base en cherchant dans la configuration de l'ORM (mapping objet-relationnel, ex: hibernate) utilisé par le serveur d'application. Il réalise les opération CRUD (create, read, update et delete) nécessaires. En résumé, l'Entity Manager gère le cycle de vie des EJB entités. Il est le pont entre le monde objet et le monde relationnel. Il réalise les opérations suivantes:
Un EJB entité devient détaché dès que l'EntityManager n'est plus accessible: sérialisation d'un entité pour le passer à un autre environnement d'exécution (ex: web tier), suppression de l'entité ou copie de l'entité. Lorsqu'un EJB entité est détaché, il n'est plus synchronisé avec la base.
Lorsque l'on manipule des objets, on manipule très rarement des objets isolés mais plutôt des objets inter-connectés formant un graphe d'objets. Si lors de l'accés à un objet, nous devions charger complétement le graphe d'objets auquels il se réfère, ce serait très coûteux en temps d'exécution (et nécessiterait aussi un espace mémoire non négligeable). C'est pour cela que, dans la mesure du possible, on ne charge les objets qu'à la demande. Afin de pouvoir gérer la stratégie de chargement, JPA fournit 2 modes pour la récupération des objets:
Mode de chargement par défaut selon les cardinalités:
Eager fetching | Lazy fetching |
---|---|
@OneToOne | @OneToMany |
@ManyToOne | @ManyToMany |
En effet, lorsqu'il n'y a qu'une entité à charger plutôt qu'une collection, il n'est pas trés coûteux de le faire.