Atelier N°3
Entreprise Java Beans avec JBOSS
Wildfly
Temps alloué Outils
6 Heures
•
•
•
•
•
Eclipse Neon
Widfly 8.2.0
Jdk 1.8/ Jdk1.7
SOAPUI5.2.1
Advanced REST Client
Objectifs
•
•
•
•
•
•
Développer une application
Gestion des Comptes avec les
EJB
Savoir déployer un datasource
pour WildFly
Créer un Session Bean
Ecrire des requêtes en HQL
Créer un web service basé sur
SOAP
Créer un web service basé sur
REST
Avant- propos :
Qu’est-ce que EJB ?
métier
distribués
.
qui s’exécutent au sein d’un conteneur EJB
Les Entreprise Java Bean ou EJB sont des composants qui permettent de
d’implémenter la logique
Ce sont des composants
qui fait partie du serveur d’application J2EE
Le but des EJB est de faciliter la création d'applications distribuées pour les
entreprises
Les EJB permettent aux développeurs de focaliser leurs efforts sur la logique
métier car il prennent en compte tous ce qui est spécifications techniques ou
non fonctionnels, tel que : la distribution, la sérialisation, la persistance, la
gestion des transactions…
Il existe trois types d’EJB : Entity Beans, Sesssion Beans et Message Driven
Beans.
I. Descriptif du travail à faire
•
•
On souhaite créer une application qui permet de gérer des comptes.
Chaque compte est défini par son code, son solde et sa date de création
L’application doit permettre de réaliser les opérations suivantes :
-
-
Ajouter un compte
Consulter tous les comptes
1
-
-
-
Consulter un compte
Effectuer le versement d’un montant dans un compte
Effectuer le retrait d’un montant d’un compte
L’application doit être accessible par :
-
-
-
Un client lourd java distant
Une application web basée sur Servlet et JSP
Un client SOAP
•
•
•
On supposera, dans un premier temps, que les comptes sont stockés dans une
liste non persistante.
Par la suite nous aborderons la persistance des comptes dans une base de
données en utilisant JPA.
II. Architecture
L’application respecte l’architecture suivante :
III. Réalisation
1. Installation du plugin Jboss Tools pour Eclipse
2
Activer Uniquement JBossASTools pour installer les outils du serveur d’application Jboss
3
2. Création d’un projet EJB
New > EJB Project
4
Après avoir spécifié le nom du projet, Cliquez sur le bouton New Runtime, pour associer
un serveur à ce projet.
3. Structure du projet EJB
5
4. Les données manipulées (Entités) : Compte.java
•
•
•
On commence par créer les structures de données manipulées par
l’application.
Il s’agit des entités (Entities) de l’application. Dans notre cas, notre
application traite des comptes. Pour le moment nous n’allons pas traiter la
persistance des entités
Nous considérons que Compte est un simple Java Bean et non pas un EJB
Entity. C’est une JPA Entity.
Dans votre projet, vous allez tout d’abord développer la couche métier. Pour ce
cas de figure ; la gestion des comptes ; la couche métier est constituée d’une
entité JPA Compte et un Session Bean Compte.
Pour pouvoir utiliser l’entité JPA "Compte", il faut avoir le fichier persistence.xml
Pour avoir ce fichier dans votre projet, il faut ajouter la facette JPA au projet ;
pour le faire allez sur les propriétés du projet et choisir la propriété "Project
Facets", cochez la facette JPA comme le montre la figure ci-dessous.
Un fichier dont le nom persistence.xml et apparu sous le dossier META-INF de
votre projet, souvenez-vous de ce fichier, son réglage est à faire juste après.
6
5. La couche métier :
1.
Créer l’entité JPA Compte tel que :
Sous ejbModule
Publicité
Sous le package metier.entities
La classe Compte générée est la suivante :
package metier.entities;
import java.io.Serializable;
import java.util.Date;
import javax.persistence.*;
import javax.xml.bind.annotation.XmlRootElement;
/**
- Entity implementation class for Entity: Compte
*
*/
@Entity
public class Compte implements Serializable {
7
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private long code;
private double solde;
private Date dateCreation;
private static final long serialVersionUID = 1L;
public Compte() {
super();
}
public long getCode() {
return this.code;
}
public void setCode(long code) {
this.code = code;
}
public double getSolde() {
return this.solde;
}
public void setSolde(double solde) {
this.solde = solde;
}
public Date getDateCreation() {
return this.dateCreation;
}
public void setDateCreation(Date dateCreation) {
this.dateCreation = dateCreation;
}
}
Puis il faut régler le fichier persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
2.
<persistence version="2.1"
xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="BanqueEJB" transaction-type="JTA"> 1
<jta-data-source>java:/dsBanque</jta-data-source> 2
<class>metier.entities.Compte</class>
<class>metier.entities.Comptee</class>
<properties>
<property name="javax.persistence.schema-
generation.database.action" value="drop-and-create"/>
</properties>
</persistence-unit>
</persistence>
8
Remarque :
1 : Pour le déploiement de la datasource ; en effet, la datasource n’est
pas créé en local, elle est déployée au niveau du serveur d’application
2 :
indépendamment du projet.
Faire le lien avec le datasource utilisée, un datasource publiée sur
l’annuaire JNDI, on a besoin d’un élément JTA tel que indiqué dans le
fichier persistence.xml ci-dessus.
Notre application dépend d’un datasource qui s’appelle dsBanque qui
va être crée indépendamment du projet.
6. Déploiement d’un datasource sur WildFly
Starting Server !
-
-
Activer la console d’administration de WildFly
Pour le faire, passer en mode invite de commande et suivre les
instructions demandées :
9
Après avoir ajouté un user, on peut administrer WildFly à partir de l’interface
d’administration web.
La figure ci-dessous est l’interface d’administration WildFly :
Comment déployer la datasource ?
10
Donnez le nom de la datasource ainsi que pour la JNDI
11
Comment ajouter le driver mysql à WildFly ?
Copier/Coller le dossier mysql qui contient le.jar du driver sous les modules de
WildFly comme le montre la figure suivante.
Dans le dossier mysql se trouve le driver
Ce n’est pas tout !
Il faut ajouter le driver dans le fichier de configuration de WildFly soit
standalone.xml, la figure suivante montre comment le faire :
12
Après cette étape d’ajout du driver mysql à WildFly où nous avons modifié le
fichier standalone.xml, il faut redémarrer le serveur.
-
-
Revenez à la console d’administration, refaire les étapes précédentes ;
Le driver mysql sera présent
Testez la connexion
13
Activez la datasource crée
Revoir la datasource dans standalone.xml
14
-
Déployez le projet et voir si la table compte a été bien introduite au
niveau de la base de données
7. Création de L’EJB Session:
remote
Un EJB Session est un composant qui possède
Local
Une interface
: qui permet de déclarer les méthodes qui sont
accessibles à distance. C’est-à-dire accessible aux composants qui sont
déployés dans d’autres machines.
Une interface
accessible en
composants déployés dans le même serveur d’application.
La
: qui permet de déclarer les méthodes qui sont
les
qui implémente les deux interfaces remote et local.
Publicité
les méthodes accessibles par
local. C’est-à-dire
classe du bean
L’implémentation des méthodes de cette classe représentent les
traitements métier de l’application
7.1. BanqueRemote.java
Une interface Remote d’un EJB Session doit être annotée @Remote
package metier;
import java.util.List;
import javax.ejb.Remote;
import metier.entities.Compte;
@Remote
public interface BanqueRemote {
public Compte addCompte(Compte cp);
public Compte getCompte(Long code);
public List<Compte> listComptes();
public void verser(Long code, double mt);
public void retirer(Long code, double mt);
public void virement(Long cp1,Long cp2, double mt);
}
15
7.2. BanqueLocal.java
Une interface Locale d’un EJB Session doit être annotée@Local
Dans notre cas, nous supposons que toutes les méthodes de l’EJB
Session son accessible à distance et en local
package metier;
import java.util.List;
import javax.ejb.Local;
import metier.entities.Compte;
@Local
public interface BanqueLocal {
public Compte addCompte(Compte cp);
public Compte getCompte(Long code);
public List<Compte> listComptes();
public void verser(Long code, double mt);
public void retirer(Long code, double mt);
public void virement(Long cp1,Long cp2, double mt);
}
7.3. BanqueEJBImpl.java
package metier;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import metier.entities.Compte;
@Stateless(name="BK")
public class BanqueEJBImlp implements BanqueLocal,BanqueRemote {
@PersistenceContext(unitName="BanqueEJB")
private EntityManager em;
@Override
public Compte addCompte(Compte cp) {
em.persist(cp);
return cp;
}
@Override
public Compte getCompte(Long code) {
Compte cp = em.find(Compte.class, code);
if(cp==null)throw new RuntimeException("Compte introuvable");
return cp;
}
16
@Override
public List<Compte> listComptes() {
Query req = em.createQuery("SELECT c FROM Compte c");
return req.getResultList();
}
@Override
public void verser(Long code, double mt) {
Compte cp = getCompte(code);
cp.setSolde(cp.getSolde()+mt);
}
@Override
public void retirer(Long code, double mt) {
Compte cp = getCompte(code);
if(cp.getSolde()<mt)throw new RuntimeException("Solde
insuffisant");
cp.setSolde(cp.getSolde()-mt);
}
@Override
public void virement(Long cp1, Long cp2, double mt) {
retirer(cp1,mt);
verser(cp2,mt);
}
}
7.4. Les annotations @Singleton, @Stateless, @Statefull
@Singleton
connexions
: Une instance unique sera créée quelque soit le nombre de
17
@Statless
: Un pool d’instances de cet EJB sera créé par le serveur
@Statfull
: Pour chaque connexion, le serveur crée une instance
Remarque :
•
•
Après instanciation d’un EJB Session, ses références Remote (IP, Port, Adresse
name
Mémoire) et Locale (Adresse Mémoire) seront publiée dans l’annuaire JNDI.
•
•
•
de ces trois annotations, permet de spécifier le nom JNDI qui
L’attribut
sera associé aux références de l’EJB dans l’annuaire JNDI.
Par défaut, c’est le nom de la classe qui sera utilisé.
Ce nom sera combiné à d’autres informations techniques pour garantir l’unicité
de ce nom.
•
Avec Jboss 7, le nom complet JNDI d’un EJB Session est de la forme suivante :
Pour un statless et singleton
Nom_Projet_EAR/Nom_Projet_EJB/Name!Package.NomInterface
18
•
Pour un statefull
Nom_Projet_EAR/Nom_Projet_EJB/Name!Package.NomInterface?statful
8. Déploiement et test de L’EJB Session
Il suffit de faire un Full Publish (republier le projet), commentez les lignes de la
console.
8.1 Client Java Remote
• Créer un nouveau projet Java pour le client
•
New > Java Project
Le client a besoin de l’interface Remote de l’EJB Session et de l’entité Compte
Publicité
• Première solution (Phase de Test):
Lier le classpath du projet client au classpath du projet EJB. De cette façon,
tous les composants du projet EJB seront accessibles au projet Java
Afficher la fenêtre propriétés du projet client java
Java Build Path > Onglet Projects > Add
19
• Ajouter jboss-client.jar au classpath du projet client
Pour accéder à distance au à l’EJB session via le protocole RMI, le client a
besoin d’un proxy dynamique (Stub) dont l’implémentation et ses
dépendances sont définies dans un fichier jar unique « jbossclient.jar
fournie par jboss.
-
-
-
Ce fichier ce trouve dans le dossier bin/client de jboss
Il faut l’ajouter au classpath du projet client
Java Build Path > Librairies > Add External JARs…
20
Propriétés JNDI
•
•
•
Pour que le client java puisse se connecter à l’annuaire JNDI pour chercher
la référence remote de l’EJB, il a besoin de connaitre un certain nombre de
jndi.properties
propriétés JNDI.
Ces propriétés sont généralement définies dans le fichier
Pour le cas de Jboss7, l’essentiel des propriétés peuvent être définie dans
le fichier
jboss-ejb-client.properties
.
Le fichier jndi.properties
java.naming.factory.url.pkgs=org.jboss.ejb.client.naming
Le fichier jboss-ejb-client.properties
endpoint.name=client-endpoint
remote.connectionprovider.create.options.org.xnio.Opt
ions.SSL_ENABLED=false
jboss-ejb-client.properties
jndi.properties
remote.connections=default
remote.connection.default.host=127.0.0.1
remote.connection.default.port = 8080
remote.connection.default.connect.options.org.xnio.Op
tions.SASL_POLICY_NOANONYMOUS=false
remote.connection.default.username=admin
remote.connection.default.password=
21
Créer la classe de Test soit ClientRemote.java
import java.util.ArrayList;
import java.util.List;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import metier.BanqueRemote;
import metier.entities.Compte;
public class ClientRemote {
public static void main(String[]args){
try {
Context ctx = new InitialContext();
String appName="BanqueEAR";
String moduleName="BanqueEJB";
String beanName="BK";
String remoteInterface="metier.BanqueRemote";
//String remoteInterface=BanqueRemote.class.getName();
String name="ejb:"+appName+"/"+moduleName+"/"+beanName+"!"+remoteInterface;
BanqueRemote proxy = (BanqueRemote)ctx.lookup(name);
proxy.addCompte(new Compte());
proxy.addCompte(new Compte());
proxy.addCompte(new Compte());
Compte cp = proxy.getCompte(1L);
System.out.println(cp.getCode()+":"+cp.getSolde());
proxy.verser(1L, 4000);
proxy.retirer(1L, 2000);
proxy.virement(1L,2L, 1000);
List<Compte> cptes = proxy.listComptes();
for(Compte c:cptes){
System.out.println(c.getCode()+":"+c.getSolde());
}
} catch (NamingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
22
8.2 Client Web
Créer un nouveau projet web dynamique qui sera déployé dans Jboss qui
s’appelle BanqueWeb
Dépendances du projet
Propriétés du projet > Java Build Path>Projects > Add
23
Structure du projet
La classe BanqueService.java
24
package service;
import java.util.Date;
import java.util.List;
import javax.ejb.EJB;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
import metier.BanqueLocal;
import metier.entities.Compte;
@WebService
public class BanqueService {
@EJB
private BanqueLocal metier;
@WebMethod
public void verser(
@WebParam(name="code")Long code,
@WebParam(name="montant")double mt){
metier.verser(code, mt);
}
@WebMethod
public void retirer(
@WebParam(name="code")Long code,
@WebParam(name="montant")double mt){
metier.retirer(code, mt);
}
@WebMethod
public void virement(
@WebParam(name="cpte1")Long code1,
@WebParam(name="cpte2")Long code2,
@WebParam(name="montant")double mt){
Publicité
metier.virement(code1,code2, mt);
}
@WebMethod
public Compte addCompte(@WebParam(name="solde")double solde) {
Compte cp = new Compte();
cp.setSolde(solde);
cp.setDateCreation(new Date());
return metier.addCompte(cp);
}
@WebMethod
public Compte getCompte(@WebParam(name="code")Long code) {
return metier.getCompte(code);
}
@WebMethod
public List<Compte> listComptes() {
return metier.listComptes();
}
}
25
Une fois le web services est terminé, il faut que le projet web et le web services font
partie du même projet d’où il on a besoin de créer un projet qui regroupe les deux
projets EJB et web services
Nommez ce projet BanqueEAR.
Choisissez les projets qui font partie de BanqueEAR
Déployez le projet BanqueEAR sur le serveur WildFly.
26
Consulter le web services et allez voir le wsdl
27
8.3 Test du web service avec SOAPUI
Créez un projet SOAP
Il suffit de donner l’url du fichier WSDL
•
•
•
Ajouter des comptes en utilisant SOAPUI
28
• Testez le versement, le retrait ainsi que le virement et la consultation de la
liste des comptes crée.
9. Le web service RESTFULL
•
La classe BanqueRestService.java
Toujours dans le projet BanqueWeb, sous le package service, vous créez
une classe java dont le nom est BanqueRestService.
package service;
import java.util.List;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import metier.BanqueLocal;
import metier.entities.Compte;
29
@Stateless
@Path("/")
public class BanqueRestService {
@EJB
private BanqueLocal metier;
@POST
@Path("/comptes")
@Produces(MediaType.APPLICATION_JSON)
public Compte addCompte(Compte cp) {
return metier.addCompte(cp);
}
@GET
@Path("/comptes/{code}")
@Produces(MediaType.APPLICATION_JSON)
public Compte getCompte(@PathParam(value="code")Long code) {
return metier.getCompte(code);
}
@GET
@Path("/comptes")
@Produces({MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML})
public List<Compte> listComptes() {
return metier.listComptes();
}
@PUT
@Path("/comptes/verser")
@Produces(MediaType.APPLICATION_JSON)
public void verser(@FormParam(value="code")Long
code,@FormParam(value="montant") double mt) {
metier.verser(code, mt);
}
@PUT
@Path("/comptes/retirer")
@Produces(MediaType.APPLICATION_JSON)
public void retirer(@FormParam(value="code")Long
code,@FormParam(value="montant") double mt) {
metier.retirer(code, mt);
}
@PUT
@Path("/comptes/virement")
@Produces(MediaType.APPLICATION_JSON)
public void virement(
@FormParam(value="cp1")Long cp1,
@FormParam(value="cp2")Long cp2,
@FormParam(value="montant")double mt) {
metier.virement(cp1, cp2, mt);
}
}
•
•
Il faut créer un contexte d’application pour pouvoir tester ce web service
Pour le faire créez une classe java soit WebApp.java
30
La classe WebApp.java
package service;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
@ApplicationPath("/")
public class WebApp extends Application {
}
Test du Web Service RESTFULL
Ou aussi
Ou avec Advanced REST Client (plug in Google chrome)
31
Test de a méthode verser
32
Testez les autres méthodes
33