Systèmes d`information répartis

Transcription

Systèmes d`information répartis
TD6 Initiation aux EJB3 avec Eclipse
Ecriture d’une application J2EE complète
Nous allons écrire une application J2EE qui permet dans un navigateur web de gérer des contacts. Pour cela, nous
allons suivre le pattern MVC (Modèle Vue Contrôleur). La vue est l’interface graphique écrite en jsp. Le contrôleur
sera écrit sous forme de servlets qui sont à même de contrôler le séquencement entre les différentes pages du projet.
Enfin, le modèle prendra la forme d’ejbs. L’architecture générale sera la suivante :
Conteneur WEB
Vue
JSP
contactForm
Conteneur d’application
Contrôleur
Servlets
AddContactForm
Servlet
Modèle
FACADE
EJB session
Remote
Stateless ou stateful
EJB entity
Local
contactAdded
AddContactExecute
Servlet
contactNotAdded
Navigateur web
listContact
ContactManager
Contact
Contact
ListContact
Servlet
Conseil : utilisez les noms de classes et de variable du TD et prenez la version de JBoss de l’archive (7.1.1)
Cette architecture est une architecture J2EE classique.
Le client
Le client est dans la zone internet, il accède de ce fait au système d'information par le conteneur web.
Les servlets
Dans ce conteneur, une ou plusieurs servlets répondent aux demandes des clients. Le conteneur web est par nature
un conteneur fragile car accessible de partout. De ce fait, il est conçu pour contenir uniquement de la présentation ou
des transferts d'information entre le cœur du SI (les processus métiers et le client). De plus, un des apports de J2EE
est de permettre de proposer plusieurs présentations différentes associées aux processus métiers. Par exemple, dans
une agence de voyage, une réservation d'un séjour peut se faire directement par client dans une interface web ou par
le personnel de l'agence dans une application java. Les processus métiers impliqués sont les mêmes mais la
présentation différente. Il faut donc être très attentif à ne pas déplacer une partie du processus métier dans les
servlets. Dans cet exemple, les servlets contiendront uniquement l'appel à l'ejb Facade.
Les ejb
Tout d'abord, la persistance des données est assurée par une base de données mysql. Pour gérer cette base, il est
classique d'associer un ejb entité par table.
Dans tous les systèmes d'information, la base de données est complexe et faite de plusieurs tables interconnectées
par des clés étrangères. De plus, un processus métier fait couramment appel à plusieurs ejb. Par exemple, pour
réserver une chambre pour un client, il faut utiliser les ejb des hôtels et des chambres pour vérifier la réservation puis
l'ejb des réservations pour rajouter la réservation mais aussi l'ejb du client pour ajouter ou rechercher le client. La
gestion de ces processus complexe doit être isolée des ejb entités qui sont chacun dédiés à la gestion d'une table.
Pour cela, une solution est de créer un ejb dit façade qui se charge des processus métiers. Cet ejb ne gère pas de la
persistance mais synchronise les appels aux ejb persistants, il s'agit donc d'un ejb session sans état.
1 Création des projets
1.1 Création du projet WEB
Une fois votre IDE Eclipse lancé cliquez sur : « File -> New ->Project -> Web -> Dynamic Web Project ». Cliquez sur
Next. Remplissez les champs comme ci-dessous. Attention, le nom de l'EAR doit être modifié.
ASI TD6 – Anne Lapujade
1
Il ne vous reste plus qu’à cliquer sur « Finish ».
1.2 Création du projet EJB
Créez un projet EJB « EJB Project » (EJB -> EJB Project). Remplissez la fenêtre comme ci-dessous :
Cliquez sur « Finish» pour terminer l’opération.
1.3 Dépendances
Le projet web va accéder aux EJB, nous devons donc créer une dépendance entre ces deux projets. Faire un clic
droit sur ProjetContactWeb -> Properties. Allez dans Java Build Path et cliquez sur l’onglet Projects. Cliquez sur Add
et sélectionnez ProjetContactEJB.
ASI TD6 – Anne Lapujade
2
Ne vous inquiétez pas si la console JBoss vous indique une erreur " No META-INF/application.xml found".
Nous créerons ce fichier par la suite. Vous pouvez arrêter JBoss.
1.4 Vues finales
Maintenant que vous avez paramétré l’ensemble des projets (Web / EJB / EAR) vous devez avoir les 4 projets
suivants dans votre package explorer :
1.5 Ajout du projet dans l’environnement d’exécution du serveur
Dans l’onglet serveur, clic droit sur JBoss puis choisir Add and remove projects. Ajouter le ProjetContactEAR :
Remarque : vous pouvez comme ci-dessus retirer ProjetEJB du serveur, nous n'en n’aurons plus besoin.
2 Les EJB - ProjetContactEJB
Nous allons mettre en place un exemple simple qui consistera à développer une application web permettant d’ajouter
et lister des contacts dans un agenda.
Notre application a besoin :
 de décrire l’entité Contact
 de gérer les instances des contacts en base de données
ASI TD6 – Anne Lapujade
3
Pour cela, nous allons utiliser :
 1 Entity Bean (permet de mapper notre entité objet Java vers une base de données)
 1 Session Bean Stateless (service façade de gestion des instances)
2.1 Entity bean
2.1.1 Base de données
Créez une nouvelle base vide nommée agenda.
2.1.2 Les EJB
Créez un package ejbAgenda dans lequel vous mettrez vos EJB
Utilisez le TD précédent pour :
 Créer la datasource
 Créer un EJB entité Contact avec les attributs suivants :
private int id;
private String prenom;
private String nom;
private String addresse;
private int codePostal;
private String ville;
private String telephone;
private String mobile;
Remarque : Clic droit + Source + Generate getter and setters permet de gagner beaucoup de temps...
 Créer un EJB façade ContactManager qui implante les méthodes suivantes :
* addContact : qui permet d’ajouter un contact
* listContact : qui retourne l’ensemble des contacts trouvés
L’implémentation de ces méthodes est la suivante :
public Contact ajouterContact(Contact contact) {
em.persist(contact);
return contact;
}
public Collection<Contact> listerContact() {
// Vous pouvez aussi utiliser une named query définie dans l’entité (cf TD5)
return em.createQuery("SELECT c FROM Contact c").getResultList();
}
Remarque : pour un même ensemble de processus métiers, il est envisageable, notamment pour des raisons de
sécurité de créer plusieurs façades différentes. Par exemple, dans le cas d'une banque, on peut avoir une façade
simplifiée pour un client distributeur de billets qui ne donne accès qu'aux méthodes du retrait et de l'édition d'un relevé
simplifié de compte. Par contre, dans le cas d'une application client destinée aux commerciaux de la banque, le
façade donnera accès à toutes les fonctionnalités de la banque.
3 Les servlets : ProjetContactWeb
Nous allons mettre en place le pattern MVC (« Modèle Vue Contrôleur ») dans notre application Web. Les servlets
sont les contrôleurs et les JSP les vues. La couche modèle est implémentée par les EJB3 Contact et
ContactManager.
Nous allons créer 3 servlets au total :
* AddContactForm : qui permettra d’afficher le formulaire d’ajout de contact
* AddContactExecute : qui ajoute le Contact avec les données du formulaire
* ListContact : qui récupère la liste des Contacts et l’affiche dans un tableau
Les classes suivantes vont être créées dans le projet ProjetContactWeb. Pour cela, clic droit sur
ProjetContactWeb > New package > nommez-le « web ».
3.1 La classe EjbLocator
Une fonctionnalité commune à ces trois servlets est la récupération du ContactManager (EJB Session). Le design
pattern « Locator » est une solution que nous allons utiliser afin de regrouper les mécanismes de localisation des EJB
au sein d’une même classe.
Créez dans le package web une classe
EjbLocator dont voici le code source :
package web;
import java.util.Hashtable;
ASI TD6 – Anne Lapujade
4
import
import
import
import
import
javax.naming.Context;
javax.naming.InitialContext;
javax.naming.NamingException;
ejbAgenda.ContactManagerRemote;
ejbAgenda.RendezVousManagerRemote;
public class EjbLocator {
private static Context ctx;
private static EjbLocator instance = new EjbLocator();
private EjbLocator() {
}
public static EjbLocator getLocator() {
return instance;
}
private <T> T getEjb(Class<T> ejbClass, String beanName) {
try {
final Hashtable jndiProperties = new Hashtable();
jndiProperties.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
final Context context = new InitialContext(jndiProperties);
final String appName = "ProjetContactEAR";
final String moduleName = "ProjetContactEJB";
return (T) context.lookup("java:global/" + appName + "/" + moduleName + "/" + beanName + "!"
+ ejbClass.getName());
} catch (NamingException e) {
return null;
}
}
public ContactManagerRemote getContactManager() {
return getEjb(ContactManagerRemote.class, "ContactManager");
}
}
Cette classe implémente le pattern Singleton afin de gérer la propre instanciation de son unique instance.
Vous pouvez remarquer l’utilisation des Generics (méthode getEjb).
3.2 La servlet d’affichage du formulaire d’ajout de contacts
Le code des servlets est alors très basique. Créez une servlet dans le package web du projet ProjetContactWeb
Fichier/Nouveau/Web/Servlet
ASI TD6 – Anne Lapujade
5
Nommez la servlet AddContactFormServlet :
Cette version d'Eclipse va générer automatiquement le mapping dans le fichier web.xml, laissez l'url-mapping par
défaut :
Nous ne générerons automatiquement que le doGet()
ASI TD6 – Anne Lapujade
6
Modifiez la méthode doGet() :
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws
IOException {
RequestDispatcher rd = request.getRequestDispatcher("/WEB-INF/jsps/contactForm.jsp");
rd.forward(request, response);
}
ServletException,
3.3 La servlet d’ajout du contact avec les données du formulaire
Répétez la même opération pour créer la servlet AddContactExecuteServlet avec un doPost cette fois-ci :
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
Contact contact = new Contact();
contact.setPrenom(request.getParameter("contact.prenom"));
contact.setNom(request.getParameter("contact.nom"));
contact.setAdresse(request.getParameter("contact.adresse"));
contact.setCodePostal(Integer.parseInt(request.getParameter("contact.codePostal")));
contact.setVille(request.getParameter("contact.ville"));
contact.setMobile(request.getParameter("contact.mobile"));
contact.setTelephone(request.getParameter("contact.telephone"));
ContactManagerRemote contactManagerRemote = EjbLocator.getLocator().getContactManager();
Contact newContact = contactManagerRemote.ajouterContact(contact);
RequestDispatcher rd = null;
if(newContact.getId() > 0) {
rd = request.getRequestDispatcher("/WEB-INF/jsps/contactAdded.jsp");
}
else {
rd = request.getRequestDispatcher("/WEB-INF/jsps/contactNotAdded.jsp");
}
rd.forward(request, response);
}
}
3.4 La servlet de récupération de la liste des contacts
Répétez la même opération pour créer la servlet ListContactServlet
protected
void
doGet(HttpServletRequest
request,
HttpServletResponse
response)
throws
ServletException, IOException {
ContactManagerRemote contactManagerRemote = EjbLocator.getLocator().getContactManager();
request.setAttribute("listContacts", contactManagerRemote.listerContact());
RequestDispatcher rd = request.getRequestDispatcher("/WEB-INF/jsps/listContact.jsp");
rd.forward(request, response);
}
3.5 Mappage des servlets
Nous utilisons ici une version plus récente de la norme Servlet que dans les TDs dédiés aux servlets qui va nous
permettre de nous affranchir du mapping dans le fichier web.xml. Ainsi par exemple, le tag
@WebServlet("/AddContactExecuteServlet") situé au début du fichier AddContactExecuteServlet.java permet tout à la
fois de déclarer que cette classe est une servlet et de donner son url-pattern.
4 L’interface graphique : les JSP
Comme nous souhaitons respecter le pattern MVC, la vue est bien entendu séparée dans des fichiers JSP. Nous
allons vous fournir l'ensemble des pages jsp.
La première contient le formulaire d'insertion des données. Il va être placé, comme toutes les autres pages JSP, dans
le répertoire "WebContent/WEB-INF/jsps/".
4.1 Formulaire de saisie d’un nouveau contact
contactForm.jsp
<html>
<head>
<title>
Contact
</title>
</head>
<body>
Ajoutons un contact : <br/>
<form method="post" action="AddContactExecuteServlet">
prénom :
<input type="text" name="contact.prenom"/><br/>
nom :
ASI TD6 – Anne Lapujade
7
<input type="text" name="contact.nom"/><br/>
adresse :
<input type="text" name="contact.adresse"/><br/>
code postal :
<input type="text" name="contact.codePostal"/><br/>
ville :
<input type="text" name="contact.ville"/><br/>
téléphone portable :
<input type="text" name="contact.mobile"/><br/>
téléphone :
<input type="text" name="contact.telephone"/><br/>
<input type="submit"/>
</form>
</body>
</html>
4.2 Affichage de la liste des contacts
Voici le code de la page listContact.jsp (page contenant le plus de code Java) :
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<%@ page import="java.util.*" %>
<%@ page import="ejbAgenda.Contact" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Liste des contacts</title>
</head>
<body>
Liste des contacts : <br/>
<br/>
<br/>
<table width="90%" >
<%
Iterator it = ((Collection)request.getAttribute("listContacts")).iterator();
while(it.hasNext()) {
Contact contact = (Contact)it.next();
%>
<tr>
<td><%= contact.getPrenom() %></td>
<td><%= contact.getNom() %></td>
<td><%= contact.getAdresse() %></td>
<td><%= contact.getVille() %></td>
<td><%= contact.getCodePostal() %></td>
<td><%= contact.getTelephone() %></td>
<td><%= contact.getMobile() %></td>
</tr>
<%
}
%>
</table>
</body>
</html>
Cette page génère le tableau des Contacts préalablement chargés par la Servlet (ListContactServlet).
Les autres pages ne contiennent que du HTML.
4.3 Attestation de l’ajout d’un contact
contactAdded.jsp
<html>
le contact a été ajouté.
</html>
4.4 Attestation du non ajout d’un contact
contactNotAdded.jsp
<html>
Le contact n'a pas pu être ajouté.
</html>
ASI TD6 – Anne Lapujade
8
4.5 Page d’accueil
index.html, qui se place à la racine de WebContent :
<html>
<head></head>
<body>
Gestionnaire de contacts
<ul>
<li/><a href="AddContactFormServlet"/>ajout d'un contact</a><br/>
<li/><a href="ListContactServlet"/>lister les contacts</a><br/>
</ul>
</body>
</html>
5 Configuration générale de l’application
Il reste à configurer le fichier .ear. Pour cela, rajouter un répertoire META-INF dans le répertoire EarContent du
ProjetContactEAR. Ajoutez un fichier application.xml dans le répertoire META-INF avec le contenu suivant :
<?xml version="1.0" encoding="UTF-8"?>
<application xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="5"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/application_5.xsd">
<display-name>Contact web application</display-name>
<module>
<web>
<web-uri>ProjetContactWeb.war</web-uri>
<context-root>/ProjetContactWeb</context-root>
</web>
</module>
<module>
<ejb>ProjetContactEJB.jar</ejb>
</module>
</application>
6 Exécution
Il faut maintenant passer à l’exécution de l’application afin de voir si tout fonctionne correctement. Il suffit de faire un
clic droit sur le ProjetContactWeb -> Run AS -> Run On Server ». Sélectionnez « JBoss -> JBoss v7.1 ». Finalement,
cliquez sur Finish.
Le plugin déploie votre application (package war, ejb, et ear) et lance le serveur.
Vous pouvez aller à l’adresse : http://localhost:8080/ProjetContactWeb
Remarque : Notez que pour ce serveur comme pour le serveur Jonas c'est Tomcat qui est utilisé comme conteneur
web.
ASI TD6 – Anne Lapujade
9
Vous pouvez tester l'ajout de contacts :
Une fois un utilisateur ajouté, vous pouvez ensuite visualiser la liste des utilisateurs. Vous pouvez aller consulter votre
base agenda, la table a été créée ainsi que les enregistrements.
ASI TD6 – Anne Lapujade
10