Cours JEE pdf avec exemples d’application pour débuter la programmation avec le langage
...
Java EE sous l ’œil de Darwin...
– J2EE 1.0 à 1.4 en 2003, etc...
– Présentation (Servlets puis JSP), essentiellement HTTP
– Logique métier : EJB
– Données : JDBC
– Facteurs de rationnalisation majeurs (JTA, JMS, JCA,
Web Services)
– Evolution de progiciels existants vers Java EE
Java EE - Architecture
Java Application Java EE Application Server
Architecture multi-tiers
– Léger (Web, browser)
– Lourd (Application java, Applet...)
– Architecture orientée service (Application répartie sans présentation)
– Conteneur EJB + logique métier
– Services non fonctionnels
Un serveur Java EE
Source : Bull/OW2 (JOnAS)
Code java exécuté sur le serveur
Équivalent du CGI
Génération de contenu Web dynamique
Mélange de HTML/XML et de code java
Librairies d ’extension (« taglibs »)
Précompilation en servlet
RMI
JNDI
– Java Naming and Directory Interface
– javax.naming
– « Service Provider » par annuaire cible (LDAP, NIS,
RMI registry...)
– Accès au bean (stub ou interface locale) pour initialiser
– Accès à diverses ressources (UserTransaction, Queues JMS, DataSources...)
JMS
– Transport synchrone ou asynchrone, Garantie de livraison
– « Messaging domains » point à point ou « publish/subscribe »
– Pour échanges asynchrones
API JavaEE de transactions : JTA
enlistResource(XAResource),
registerSynchronisation(Synchronization) ...
JTA : Participants
beforeCompletion( ) équivaut à prepare( )
API XA de JavaEE
getConnection( ) et getXAResource( ))
JMX
– API unique pour applications de management
– Typage faible, attributs nommés
– Enregistrement des Mbeans
– Les applis d ’administration dialoguent avec le serveur JMX
– Fournir un ou des Mbeans
– Les enregistrer auprès du serveur JMX
JMX : Exemple d ’un serveur JavaEE
Sécurité : JAAS
– Authentification : s'assurer que le client est bien celui qu'il prétend être.
– Autorisation (ou « habilitation ») : s'assurer qu'il détient les droits de faire ce qu'il demande.
– ex. administrateur, développeur, etc...
– La gestion des associations nom/ mot de passe ou certificat / rôle est sous-traitée à un « Realm » (peut utiliser différentes techniques : fichier de conf, base de données, LDAP...)
– Pour les clients lourds java, APIs clientes JAAS pour implémenter l'intéraction avec l'utilisateur (ex. saisie du mot de passe...)
EJB : Architecture
– JNDI, JTA/JTS, JDBC, JMS , JAAS
EJB : Gamme de services implicites
=> Le développeur se focalise sur les aspects métier
Conteneur EJB
Simplification : 1 classe, 1 ou 2 interfaces
- L’interface Home (cycle de vie) disparaît
Le descripteur de déploiement devient facultatif
- Remplacé par des annotations java dans le bean
- Si présent tout de même, priorité au DD sur les annotations
EJB : Interface métier
EJB - au moment du déploiement
Exemple : interface métier
package facturation;
public interface FacturationRemote {
void init( );
void creerFacture(String numfact, double montant);
Facture getFacture(String numfact);
// ...
}
EJB : Implémentation du Bean
– Type de bean
– Comportement : transactions, sécurité, persistance...
– Callbacks conteneur
Exemple : Implém. de Bean
package facturation;
@Stateful (mappedName=« Facturation »)
@Remote(FacturationRemote.class)
public class FacturationBean implements FacturationRemote {
void init( ) {
// ...
}
Facture getFacture(String numfact) {
// ...
}
// ...
}
EJB : Code client
Context ctx = new InitialContext();
// appel JNDI pour obtenir une référence
//à l’interface
FacturationRemote fact =
(FacturationRemote)ctx.lookup(
“Facturation”);
// appel méthode métier
Facture f = fact.getFacture(numfact);
EJB : Entité
– Pas d’accès BD dans le code.
– Pour les EJB3, utilisation de JPA (Java Persistence API)
EJB : Bean Session
=> Un Bean Stateful encapsule la logique métier et l’état specifiques à un client
EJB : Message Driven Bean
– Méthode onMessage( )
– Appels à d’autres beans, etc...
– Associations Bean / ressource JMS
– Ressources JMS (ex. Queue ou Topic)
Message Driven Bean : exemple
Appli :
Client
JMS
Message Driven Bean : exemple (2)
public class StockHandlerBean implements javax.jms.MessageListener {
...
public void onMessage(Message message) {
...
sh = (StockHome)initialContext.lookup("java:comp/env/ejb/Stock");
queue = (Queue)initialContext.lookup("java:comp/env/jms/Orders");
...
MapMessage msg = (MapMessage)message;
pid = msg.getString("ProductId");
qty = msg.getString( "Quantity");
cid = msg.getString("CustomerId");
Stock stock = sh.findByPrimaryKey(pid);
stock.decreaseQuantity(qty);
...
qs = session.createSender(queue);
TextMessage tm = session.createTextMessage();
String m = "For CustomerId = "+cid+" ProductId= "+pid+" Quantity= "+qty;
tm.setText(m);
qs.send(tm);
...
}
MDB : Annotations
@MessageDriven(activationConfig = {
@ActivationConfigProperty(
propertyName=« destination »,
propertyValue=« SampleQueue »),
@ActivationConfigProperty(
propertyName=« destinationType »,
propertyValue=« javax.jms.Queue »)
}
EJB : Configuration & Déploiement
– Description du Bean (Entity ou Session, ...)
– Ressources (Base de données,...)
– Securité: permissions et rôles
– Persistance (BMP, CMP)
– Attributs transactionnels
–
...
Priorité au descripteur de déploiement sur les annotations.
=> Utilisé par l’assembleur d’application et par le conteneur EJB au moment du déploiement
Descripteur de déploiement (optionnel)
EJB Facturation
Facturation
facturation.FacturationRemote
facturation.FacturationBean
Stateful
Container
jdbc/facturationDB
javax.sql.DataSource
Container
Ressources et JNDI
– Noms préfixés par le type de ressource référencée
(ejb, jms, jdbc, mail, url...)
Fournisseur f =
(FournisseurRemote)initialContext.lookup(
"java:comp/env/ejb/Fournisseur");
bd = (DataSource)initialContext.lookup(
"java:comp/env/jdbc/Compta");
Lookup et Stateful Session
CartBean c =
(CartBean)httpSession.getAttribute(« caddie »);
if(c == null) {
c = initialContext.lookup(« ShoppingCart »);
httpSession.setAttribute(« caddie », c);
}
Optimisations par le conteneur
– Pool d’instances
– Le serveur peut y accéder via un pool de threads
– Activation / Passivation (appel par le container des callbacks annotées @PostActivate après activation / @PrePassivate avant passivation)
– Callbacks annotées @PostConstruct et @PreDestroy
– Gestion possible des callbacks par un Callback Listener (annotation @CallbackListener dans le bean pour spécifier la classe chargée de gérer les callbacks conteneur).
Injection de dépendances
– Alternative au lookup JNDI
– Interne au conteneur (pas client distant !)
– @EJB private CalculatorLocal calc; // Injection d’EJB (local)
– @Resource javax.sql.DataSource ds; // Injection de ressource
Intercepteurs : @AroundInvoke
– Identification de l’appel (méthode, classe...) : paramètre
InvocationContext
– @AroundInvoke
public Object intercept(InvocationContext ctx) throws Exception {
String method = ctx.getMethod().getName();
//Avant invocation...
try { return ctx.proceed(); } catch(Exception e) { throw e; }
finally {
// Apres invocation...
}
processing...
Intercepteur : classe dédiée
– Les callbacks d’interception sont regroupées dans une classe dédiée
– @Stateless
@Interceptors (Intercept.class)
public class CalculatorBean { ... }
– public class Intercept {
@AroundInvoke
public Object intercept(InvocationContext ctx)
throws Exception {
String clazz = ctx.getClass().getName();
//...
return ctx.proceed();
}
Persistance EJB3
– Mapping objet / relationnel
– Pluggable sur différents frameworks de persistance (JDO, Hibernate,
TopLink, etc...) via un « persistence provider ».
– Gestion déclarative (annotations)
– Classe persistante : « entité » ( @Entity )
– Champs persistants : variables d’instance (« access=FIELD ») ou propriétés avec méthodes get/set (« access=PROPERTY »).
– Présence obligatoire d’un constructeur sans argument (et implémentation de java.io.Serializable si transféré côté client).
– Relations entre instances d’entités (cardinalité 1-1, 1-N, N-P, uni ou bi
directionnel)
– Basé sur SQL92 (« select... from... where »)
– Méthodes associées à des requêtes avec paramètres
Exemple
@Entity
public class Facture implements java.io.Serializable {
private int numfact;
private double montant; private Client client;
public Facture() { } // Constructeur par défaut (obligatoire pour Entity bean) public Facture(String numfact) { this.numfact = numfact; }
@Id
public int getNumfact() { return numfact; }
public void setNumfact(int nf) { numfact = nf; }
public void setMontant(double montant) { this.montant = montant; } public double getMontant( ) { return montant; }
@ManyToOne
@JoinColumn (name = “refclient”)
public Client getClient( ) { return client; }
public void setClient(Client client) { this.client = client; }
Exemple (2)
@Stateless
@Remote(FacturationRemote.class)
public class FacturationBean implements FacturationRemote {
@PersistenceContext
private EntityManager entityManager = null;
public void creerFacture(String numfact, double montant) { Facture fact = new Facture(numfact); fact.setMontant(montant);
} entityManager.persist(fact);
public Facture getFacture(String numfact) {
return entityManager.find(Facture.class, numfact);
}
Relations
– Exemple : classe Client, lien OneToMany avec la classe Facture
– Lien Client/Factures : la Facture est « propriétaire » de la relation
– Attribut « mappedBy » côté Client, et joinColumn côté Facture
– Exemple : Fournisseur et Adresse
– Exemple : Client et Facture
– Exemple : Facture et Client
– Exemple : Produit et Fournisseur
Relations et matérialisation
– Buffer avec pré-fetch.
– @OneToMany(fetch=FetchType.EAGER)
EntityManager
EntityManager.persist ( entité )
– Nouvelle entité passe en état géré, ignore les entités supprimées
– Cascade sur relations annotées cascade=PERSIST ou
ALL
– Envisager un merge ( ) ?
EntityManager.remove ( entité )
– Ignore les entités nouvelles ou supprimées
– Cascade sur relations annotées cascade=REMOVE
ou ALL
IllegalArgumentException
– Envisager un merge ( ) ?
EntityManager.flush( )
– Cascade sur relations annotées cascade=PERSIST ou ALL
EJB-QL
– « select... from ... where » sur des objets
– « update » et « delete »
– « join », « group by... having »
– Possibilité de requêtes paramétrées
– Utilisation directe, ou requêtes nommées (@NamedQuery)
public List listFactures( ) {
Query qry = entityManager.createQuery(
« select f from Facture f »); return qry.getResultList();
Callbacks cycle de vie
– Annotations @PrePersist, @PostPersist, @PreRemove,
@PostRemove, @PreUpdate, @PostUpdate, @PreLoad
– Gestion possible par une classe dédiée
@EntityListener(MyListener.class)
L’instance cible est passée en paramètre aux callbacks
@PreRemove
void preRemove() {
System.out.println(« Avant suppression »);
Pattern « ValueObject » revisité
– Récupération de l’objet côté client
– L’objet est détaché du contexte de persistance (incompatible avec LAZY loading...)
– Appels méthodes getXXX( ) et/ou setXXX( )
– persistentObj = entityManager.merge(obj);
– Pas de cascade avec LAZY loading... donc EAGER !
– Graphe d’objets sérialisé si dépendances (utiliser transient si nécessaire)
Définition fine du mapping O/R
– ONLY_ONE_TABLE (défaut) : 1 table pour 1 hiérarchie de
classes (les colonnes représentent tous les champs persistants
possibles), @DiscriminatorColumn et attribut
DiscriminatorValue de @Inheritance
– TABLE_PER_CLASS : 1 table par classe
– JOINED : Table spécifique pour les champs d’une classe
fille, jointure avec celle de la classe parente.
Mapping ONLY_ONE_TABLE
I
Entity Inheritance(discriminatorValue=« P ») DiscriminatorColumn(name=« typepersonne ») public class Personne implements Serializable { //...
}
@Entity
@Inheritance(discriminatorValue=« E »)
public class Employe extends Personne {
//...
}
Transactions
– Session, Entité, Message driven
« NotSupported » seulement).
– Utilisation de javax.transaction.UserTransaction (JTA)
– Contrôle de la transaction (timeout, « rollbackOnly »)
– Exemple
UserTransaction utx =
(UserTransaction)ctx.lookup(« java:comp/UserTransaction »);
utx.begin();
...
utx.commit();
Gestion déclarative des transactions
– Si pas de transaction, nouvelle transaction
– Si transaction courante, l’utiliser
– Si transaction courante, elle est suspendue
– Nouvelle transaction (si tx courante, suspendue)
– Exception si pas de transaction courante
– Exception si transaction courante
Annotations : Gestion déclarative des transactions
@TransactionManagement(javax.ejb.TransactionManagementType.CONTAINER)
public class Facturation implements FacturationRemote {
@TransactionAttribute(javax.ejb.TransactionAttributeType.REQUIRED)
public void creerFacture( ) {
// ...
}
}
Descripteur de déploiement :
Gestion déclarative des Transactions
Facturation
*
Required
NotSupported
Required
RequiresNew
Mandatory
Supports
Never
Gestion des événements transactionnels (Session Bean)
– Implantation de javax.ejb.SessionSynchronization
– afterBegin : appelé après UserTransaction.begin
– beforeCompletion : appelé avant
UserTransaction.commit
– afterCompletion(true | false) : appelé après commit
ou rollback
Sécurité : gestion déclarative
@Stateful
@RolesAllowed( { « comptable », « logisticien » } )
public class Fournisseur implements FournisseurLocal {
// ...
}
LDAP ou base de données) sont déclarés par configuration au niveau du serveur (chaque serveur dispose de mécanismes spécifiques).
Sécurité : Descripteur de déploiement
...
comptable
Fournisseur
*
Sécurité : domaine de protection
– Le conteneur (ou un ensemble de conteneurs)
– A l'intérieur, pas de nouvelle authentification
– Annotation @RunAs ( « identité » )