1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 

EJB 3 - Les Entreprise Java Bean version 3 (JavaBeans)

2.3.Spécifications des différents beans

Les différents composants d’un bean (classe / interface / descripteur de déploiement) se simplifient avec la version 3. Nous allons voir en détails chacun de ces changements.

2.3.1.Classe bean et interfaces

        1. Classe bean

Le développeur définit la classe de l’entreprise bean et l’annote en utilisant le concept de metadata en Java. Ces annotations peuvent être appliquées à la classe du bean pour spécifier les informations liées au conteneur, pour demander un service ou encore pour fournir différentes informations de configuration pour le deployer.

L’élément requis par la classe du bean est la définition du type de bean à utiliser (Stateless   Statefull   Entity  ). Il est bien entendu possible de ne pas utiliser les annotations metadata et utiliser alors un descripteur de déploiement.
          1. Interfaces

Dans EJB 3, les interfaces sont des « pures » interfaces java. C'est-à-dire que vous n’avez plus besoin d’hériter de « EJBObject » ou « EJBLocalObject ».
            1. Business (métier)

Seuls les session bean et les message driven bean ont besoin d’une business interface (nous verrons plus tard comment cela se passe avec les entity bean). Cependant les message driven bean utilise typiquement l’interface javax.jms.MessageListener (à cause de l’API JMS : Java Message Service).

La classe bean peut implémenter directement l’interface métier. Une classe bean peut cependant implémenter plusieurs interfaces à la fois à condition de respecter ces quelques règles :
  • Si le bean implémente qu’une seule interface, alors ça doit être l’interface métier (business). Celle-ci doit donc être la local ou la remote (ou bien entendu les deux) et l’interface doit porter l’annotation indiquant le type d’interface (Local   Remote  )
  • Un bean peut implémenter plusieurs interfaces. Dans ce cas, chacune des interfaces doit explicitement être marquée par les annotations indiquant le type de l’interface métier (Local ou Remote).
  • Une interface métier ne doit pas étendre javax.ejb.EJBObject ou javax.ejb.EjbLocalObject

Les annotations liées aux interfaces sont :
  • @Local : pour spécifier que l’interface est de type local
  • @Remote : pour spécifier que l’interface est de type remote



            1. Exceptions

Les méthodes des interfaces métiers peuvent déclarer des exceptions liées à l’application. Cependant vous n’avez plus à spécifier, pour les méthodes de la remote interface, l’exception : java.rmi.RemoteException.
Si un problème survient au niveau du protocole, une EJBException est jetée par le conteneur.
            1. Home

Les home interfaces ont été éliminées.
Les sessions beans n’ont plus besoin d’avoir de home interface. Un client peut acquérire une référence du session bean directement.
En ce qui concerne les Entity, la création d’entité se fait simplement par l’opérateur new (d’instantation) et par l’utilisation de l’EntityManager API (vu plus loin dans l’essentiel).

2.3.2.Callbacks et Classe Listener Callback

Une méthode peut être définie comme étant une méthode « callback » afin de recevoir une notification au niveau du cycle de vie d’un session ou message-driven bean.
Les méthodes « callback » doivent être annotées avec les annotations de callback.

Voici un example :

@Stateful public class ShoppingCartBean implements ShoppingCart {
private float total;
private Vector productCodes;
public int someShoppingMethod(){...};
...
@PreDestroy endShoppingCart() {...};
}


Vous pouvez définir des méthodes callback directement dans la classe de votre bean. Dans ce cas, la signature de votre méthode doit respecter : public void <METHOD> ()

Cependant vous pouvez également utiliser une classe « listener de callback » qui peut être utilisée à la place des méthodes intégrées au bean. Cela dans le but de séparer le traitement du cycle de vie du traitement logique lié au bean.
Dans ce cas, il vous faudra utiliser l’annotation CallbackListener dans la classe du bean avec laquelle vous voulez associer votre classe listener.
Une classe listener callback doit définir obligatoirement un constructeur public ayant aucun argument.
Les annotations utilisées dans la classe listener sont les mêmes que celles utilisées dans la classe du bean. Cependant la signature des méthodes de la classe listener est : public void METHOD (Object) où Object est le type du bean actuel.



2.3.3.Session Bean

        1. Stateless

          1. Bean

La classe du bean doit être annotée avec « @Stateless ». Cette classe n’a pas à implémenter l’interface javax.ejb.SessionBean.
          1. Callbacks

Les session bean supportent les callback d’évènement suivant :
  • PostConstruct
  • PreDestroy

La callback PostConstruct intervient après toutes les dépendances d’injection effectuée par le conteneur et avant le premier appel de la méthode métier.
La callback PreDestroy est appelée au moment ou l’instance de du bean est détruite.
          1. Dépendance d’injection

Si un session bean utilise le mecanisme de dépendance d’injection afin d’acquérir des références à d’autres ressources ou d’autres objets de l’application, alors le conteneur injecte ces références avant que toute méthode liée au cycle de vie de l’EJB ou méthode métier soit appelée.
          1. Interceptor

Il est possible de créer des méthodes d’interception d’appel des méthodes métiers d’un bean. Ces méthodes peuvent être définies directement dans le bean ou dans une classe d’interceptor et appliquées aux méthodes métiers du bean.
          1. Exemple

Voici un exemple très simple de SessionBean (type stateless). Il faut bien entendu définir la ou les interface(s) que notre bean va implémenter. Ici nous définissons simplement l’interface Remote qui contient une seule méthode : getHello(). De plus nous l’annotons avec l’annotation @Remote afin de la déclarer comme interface distante. Cependant il est possible de ne pas l’annoter directement mais de la déclarer dans la classe du Bean, cela permet une entière compatibilité avec des clients utilisant la JVM 1.4.

Voici le code de l’interface distante (Remote) :

import javax.ejb.Remote;

@Remote
public interface RemoteHello {
public String getHello();
}

La classe du bean implémente l’interface précédente et est annotée par @Stateless afin de la déclarée comme Session Bean Stateless.
Voici le code de cette classe :

import javax.ejb.Stateless;

import com.society.testejb3.interfaces.RemoteHello;

@Stateless
public class HelloBean implements RemoteHello {

public String getHello() {
return "Hello world";
}
}


        1. Stateful

Statefull session bean a les mêmes caractéristiques que le Stateless. Seuls les points en plus sont expliqués dans les sections ci-dessous.
          1. Bean

La classe du bean doit être annotée avec « @Statefull ». Cette classe n’a pas à implémenter l’interface javax.ejb.SessionBean.
          1. Callbacks

Les session bean supportent les callback d’évènement suivant :
  • PostConstruct
  • PreDestroy
  • PostActivate
  • PrePassivate

Les callback PrePassivate et PostActivate représentent les anciennes méthodes : « ejbActivate » et « ejbPassivate ».
          1. Removal method

L’annotation @Remove permet de définir une méthode indiquant la suppression du Statefull Bean lorsque cette méthode aura fini son exécution (exécution normal ou anormale).

2.3.4.Entity Bean

Les entity beans subissent de grandes modifications avec la version EJB3. En effet, les spécifications ce ceux-là sont séparées de celles des Session Bean et Message Driven. Nous allons donc voir l’ensemble des besoins et spécifications que les entity bean doivent respecter.
        1. Bean Class

La classe du bean doit tout d’abord être annotée avec @Entity. Le constructeur doit avoir aucun argument (comme le constructeur par défaut) mais il se peut que la classe ait d’autres constructeurs en plus de celui-là.
Ce constructeur doit être public ou protected.
Si l’entity a la possiblité d’être utilisé comme objet détaché (comme dans une relation client de type Remote), la classe doit implémenter l’interface java.io.Serializable.
La classe de l’entité ne doit pas être finale et aucune de ses méthodes aussi.

Les entités supportent l’héritage, le polymorphisme. Une classe abstraite peut être une entité.
L’état d’une entité est représenté par des variables d’instances qui doivent correspondrent à des propriétés JavaBean.
          1. Champ persistants & propriétés

L’état persistant d’une entité est accessible par l’implémentation du fournisseur de persistance soit comme dans le cas des JavaBeans soit par les variables d’instances.
  • Si l’entité est annotée avec access=FIELD, le fournisseur accède directement aux variables d’instances que ne sont pas Transient, afin de les rendre persistantes.
  • Si l’entité est annotée avec access=PROPERTY, le fournisseur accède aux champs persistants par le biais des méthodes setter/getter. Celles-ci doivent être public ou protected.

Vous pouvez utiliser les collections dans vos JavaBeans, les types supportés sont : java.util.Collection, java.util.Set, java.util.List, java.util.Map.
L’utilisation des génèriques est également possible, par exemple : Set<Order> est autorisé.

Vous pouvez utiliser l’ensemble des types suivants pour vos champs persistants : java.lang.String, java.math.BigInteger, java.util.Date, java.util.Calendar, java.sql.Date, java.sql.Time, java.sql.Timestamp et les tous types sérializables.
          1. Création d’instance

La création d’instance d’une entité, se fait simplement par la simple instanciation de la classe par l’opréateur new. Cependant la persistance de l’objet créé est réalisée avec l’EntityManager API. Nous verrons cela plus en détail ci-dessous.
          1. Primary key & Identité

Une simple clé primaire (non composite) doit correspondre à un simple champ persistant ou une propritété de la classe. Une clé composite doit également correspondre soit à un champ persistant soit à un ensemble de champs ou propriétés. Une classe pour la clé primaire doit impérativement être définie pour représenter une clé composite. Vous utiliserez une clé composite lorsque vous ferez un mapping avec une base de données dans laquelle la clé est composée de plusieurs champs.

Le type de la clé primaire peut être : n’importe quel type primitif de java, n’importe quel wrapper (Integer, Double …), java.lang.String, java.util.Date, java.sql.Date.
On n’utilise généralement pas des types float ou double en tant que clé primaire.

Voici les différentes règles à respecter pour une clé primaire composite :
  • La classe de la clé primaire doit être public et doit avoir un construteur public sans argument
  • Si l’accès est de type PROPERTY, la classe peut être soit public soit protected
  • La classe doit être Serializable
  • La classe doit définir les méthodes equals et hashCode
  • Si la clé primaire est mappée à de multiples champs ou propriétés, le noms des champs de la clé primaire doivent être les mêmes que ceux utilisés dans le bean.
          1. Mapping par défaut

Lorsque vous allez créer votre bean, il vous faudra mapper l’ensemble de vos champs. Cependant il est possible d’utiliser le mapping par défaut. Ce mapping sera utilisé lorsque vous n’aurez pas utilisé d’annotation pour un champ (qu’il soit persistant ou relationnel).

Le mapping standard est utilisé lorsque c’est un champ persistant (non relationnel) : @Basic.
          1. Exemple simple

Voici un exemple de POJO (Plain Oriented Java Object) simple. Il permet de définir la structure de la table « COUNTRY ». Il implémente Serializable afin de pouvoir être envoyé directement à un client distant (et donc de passer à travers un réseau).
Les annotations obligatoires sont :
  • @Entity qui déclare la classe comme étant une entité
  • @Id qui déclare la clé primaire (generate permet de définir le type de génération à utiliser pour cette clé. GeneratorType.AUTO définit une clé auto incrémentée).
Les autres annotations ne sont pas obligatoires mais permettent de spécifier plus précisément différents paramètres :
  • @Table définit le nom de la table à utiliser
  • @Basic définit le type d’un champ persistant (par défaut cet type est utilisé)

import java.io.Serializable;

import javax.persistence.Entity;
import javax.persistence.GeneratorType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "COUNTRY")
public class Country implements Serializable {
private int id;
private String name;
public Country() { }

@Id(generate = GeneratorType.AUTO)
@Basic
public int getId() { return id; }
public void setId(int id) { this.id = id; }

public String getName() { return name; }
public void setName(String name) { this.name = name; }
}



          1. Relations

Les relations entre entités peuvent être: one-to-one, one-to-many, many-to-one, many-to-one, many-to-many.
Si vous souhaitez relier deux entités, vous pourrez utiliser les annotations : OneToOne, OneToMany, ManyToOne, ManyToMany. Pour les associations qui ne spécifient pas le type de bean « target » (utilisation de Collection sans les génériques), il est nécessaire de spécifier l’entité qui est la cible.

Les relations peuvent être unidirectionnelles ou bidirectionnelles.Un relation bidirectionnelle est accessible des deux côtés (des deux beans) alors qu’une relation unidirectionnelle n’est valable que depuis un bean.

Voici les règles à respecter pour les relations :
  • L’inverse parti d’une relation bidirectionnelle doit être référencée par l’utilisation de l’attribut mappedBy des éléments : OneToOne, OneToMany, ManyToOne, ManyToMany. Cet attribut désigne la propriété ou le champ de l’entité qui est le propriétaire de la relation.
  • Vous n’avez pas besoin de définir l’attribut mappedBy dans le cas des relations bidirectionnelles OneToMany et ManyToOne.
  • Pour les relations OneToOne, la partie propriétaire correspond à la partie contenant la clé étrangère.
  • Dans le cas de la relation ManyToMany, les deux côtés sont propriétaires !
          1. Exemple relationnel

Ce bean intègre une relation avec un autre bean de type : ManyToOne. Nous pouvons remarquer que cette relation met en évidence un champ de type Country dans ce bean.
L’utilisation des annotations relationnelles décrit plus en détail la relation :
  • @ManyToOne définit le type de la relation (ManyToOne)
  • @JoinColumn définit la colonne de jointure pour cette relation

package com.society.stockmanager3.entities.beans;

import java.io.Serializable;

import javax.persistence.Entity;
import javax.persistence.GeneratorType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

@Entity
@Table(name = "CITY")
public class City implements Serializable {
protected int id;

protected String name;

protected Country country;

public City() {
}

public City(String name) {
this.name = name;
}

@ManyToOne(optional = false)
@JoinColumn(name = "countryId")
public Country getCountry() {
return country;
}

public void setCountry(Country country) {
this.country = country;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

@Id(generate = GeneratorType.AUTO)
public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}
}


          1. Héritage

Une entité peut hériter d’un autre. Les entités supportent l’héritage, l’association polymorphique, les requêtes polymorphiques.
Les classes abstraites ou concrètes peuvent être des entités.
Des entités peuvent hériter de classes (non entité) et inversement.
Lorsqu’une entité hérite d’une autre entité, les clés primaires doivent être du même type.
            1. Abstract class

Une classe abstraite peut être une entité. La différence avec une classe concrète est qu’il n’est pas possible d’instancier cette entité directement. Cependant vous pouvez utiliser la classe abstraite en tant que target dans une requête (ce qui vous permettra par exemple de récupérer l’ensemble des sous types de votre abstract classe).
Vous devez bien entendu définir votre classe abstraite comme une entité (via Entity).
            1. Héritage

Une entité peut avoir une classe parente (abstract ou concrète) qui ne soit pas une entité. La superclasse sert seulement pour l’héritage d’un comportement. En effet, aucune des proprités de la super classe (non entité) ne sera rendu persistante.
Vous ne pourrez pas passer en argument une classe « non entité » à l’EntityManager.

Il existe 3 stratégies de mapping :
  • Une table pour une hiérarchie de classe
  • Une table par classe concrète
  • Stratégie consistant à séparer les champs spécifiques d’une classe fille dans une table séparée par rapport à la table contenant les données de la table parente. Une jonction est alors faite pour instantier la classe fille.
              1. Une table pour une hiérarchie de classe

Dans cette stratégie, toutes les classes de la hiérarchie sont mappées dans une même et unique table. La table a une colonne qui définit le type de données (pour l’enregistrement).
Cette stratégie fournit de nombreux avantages concernant les relations polyphormiques entre entités et pour les requêtes.

Cependant, les données utilisent plus de place car l’ensemble des colonnes n’est pas toujours utilisé (suivant le type de données enregistrées).
                1. Exemple

Voici un exemple d’héritage de type : ONLY_ONE_TABLE (cela est fait par l’utilisation de l’annotation @Inheritance, c’est le type par défaut d’héritage). Il faut définit une colonne permettant de différencier les différents types d’entité (cela est effectuée par @DiscrimanatorColumn). De plus il faut indiquer la valeur de « descriminitation » pour chaque entité (via discriminatorValue, attribut de @Inheritance).

import java.io.Serializable;

import javax.persistence.DiscriminatorColumn;
import javax.persistence.Entity;
import javax.persistence.GeneratorType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

@Entity
@Table(name = "record")
@Inheritance(discriminatorValue="B")
@DiscriminatorColumn(name="record_type")
public class Record implements Serializable {
protected int id;

protected double saving;

protected double result;

public Record() {
}

public Record(int id, double result, double saving) {
this.id = id;
this.result = result;
this.saving = saving;
}

@Id(generate = GeneratorType.AUTO)
public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

public double getResult() {
return result;
}

public void setResult(double result) {
this.result = result;
}

public double getSaving() {
return saving;
}

public void setSaving(double saving) {
this.saving = saving;
}

public void setFund(Fund fund) {
this.fund = fund;
}

public void setInvestor(Investor investor) {
this.investor = investor;
}

}


Voici la classe fille TimeRecord :

import java.sql.Timestamp;

import javax.persistence.Entity;
import javax.persistence.Inheritance;

@Entity
@Inheritance(discriminatorValue = "T")
public class TimeRecord extends Record {

private Timestamp ts;

public TimeRecord() { }

public TimeRecord(double result, double saving, Timestamp ts) {
super(id, result, saving);
this.ts = ts;
}

public Timestamp getTs() {
return ts;
}

public void setTs(Timestamp ts) {
this.ts = ts;
}
}


Voici le résultat au niveau de la base de données (une seule table pour deux entités) :


              1. Une table par classe concrète

Chaque concrète classe est liée à sa propre table. Cela signifie que toutes les propriétés de la classe (incluant les propriétés héritées) sont mappées dans la table liée à la classe.

Voici les inconvénients de cette statégie :
  • Mauvaise gestion des relations polymorphiques
  • Le SGDB doit effectuer une requête de type UNION pour récupérer l’ensemble des données de l’ensemble de la hiérarchie des classes.
                1. Exemple

Voici un exemple d’utilisation de l’héritage de type : TABLE_PER_CLASS. Une petite modification a également été faite au niveau des accès aux données. L’accès se fait directement via les variables d’instances (définit via access=AccessType.FIELD) ; ce type d’accès vous évite de créer des getters et setters pour chacune de vos propriétés. Le type d’héritage est déclarée dans l’annotation @Inheritance grâce à l’attribut (strategy=InheritanceType.TABLE_PER_CLASS).


import javax.persistence.AccessType;
import javax.persistence.Basic;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;

@Entity(access=AccessType.FIELD)
@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
public abstract class Animal {

@Id protected Integer id;
@Basic protected String name;
@Basic protected Integer age;

public Animal() {
}
}


Voici une classe fille : Bird de la classe Animal :

import javax.persistence.AccessType;
import javax.persistence.Basic;
import javax.persistence.Entity;

@Entity(access=AccessType.FIELD)
public class Bird extends Animal {

@Basic protected Integer nbPlume;

}


Voici une classe fille : Dog de la classe Animal :

import javax.persistence.AccessType;
import javax.persistence.Basic;
import javax.persistence.Entity;

@Entity(access=AccessType.FIELD)
public class Dog extends Animal {

@Basic protected String race;

public Dog() {
}

}


Voici le résultat en base de données (toutes les données sont intégrées dans chacune des tables) :


              1. Une table pour une partie de données spécifiques

Dans cette stratégie, la classe mère des entités est représentée par une simple table. Chaque sous classe est représentée par une table séparée contenant l’ensemble des propriétés spécifiques à la classe fille (et bien entendu la clé primaire). La clé primaire de la classe parente est utilisée comme clé étrangère avec la clé primaire de la classe fille.

Cette stratégie fournit un bon support pour les relations polyphormiques entre entités.

L’inconvénient est qu’elle requière l’utilisation de plusieurs jointures entre les tables lors de la récupération de données. Dans le cas de hiérarchie importante (grande profondeur de hiérarchie) cela peut entrainer de mauvaise performance.
                1. Exemple

Seul le type d’héritage change dans cet exemple. Il est déclaré à : « InheritanceType.JOINED ».

import javax.persistence.AccessType;
import javax.persistence.Basic;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.Version;

@Entity(access=AccessType.FIELD)
@Inheritance(strategy=InheritanceType.JOINED)
public abstract class Employee {

@Id protected Integer id;
@Version protected Integer version;
@Basic protected String name;

public Employee() {
}
}


Voici une classe fille PartTimeEmployee de Employee :

import javax.persistence.AccessType;
import javax.persistence.Basic;
import javax.persistence.Entity;
import javax.persistence.Inheritance;
import javax.persistence.PrimaryKeyJoinColumn;

@Entity(access=AccessType.FIELD)
@Inheritance(discriminatorValue="PT")
@PrimaryKeyJoinColumn(name="PT_EMPID")
public class PartTimeEmployee extends Employee {

@Basic protected Float hourlyWage;

public PartTimeEmployee() {
}
}


Voici une classe fille FullTimeEmployee de Employee :

import javax.persistence.AccessType;
import javax.persistence.Basic;
import javax.persistence.Entity;
import javax.persistence.Inheritance;
import javax.persistence.PrimaryKeyJoinColumn;


@Entity(access=AccessType.FIELD)
@Inheritance(discriminatorValue="FT")
@PrimaryKeyJoinColumn(name="FT_EMPID")
public class FullTimeEmployee extends Employee {

@Basic protected Integer salary;

public FullTimeEmployee() {
}
}


Voici le résultat au niveau de la base de données (optimisation de la place prise par les données) :


        1. Opérations sur les entités

Nous allons décrire, dans cette partie, l’utilisation de l’EntityManager API afin de gérer le cycle de vie d’une instance d’entité et l’utilisation de l’API Query qui permet d’exécuter des requêtes sur des objets persistants.
          1. EntityManager

Une instance d’un EntityManager est associée avec un contexte de persistance. Ce contexte est un ensemble d’instances d’entités pour lequel pour n’importe quelle entité, il existe une unique instance de l’entité. Grâce à ce contexte, les instances d’entités et leur cycle de vie peuvent être gérés.

The EntityManager interface définit l’ensemble des méthodes que l’on peut utiliser pour intérargir avec le contexte de persistance. Cette API est utilisée pour créer et supprimer des instances d’entités ou encore pour en trouver via leur clé primaire ou par le biais de requêtes sur les objets eux-mêmes.

L’ensemble des entités qui peuvent être gérer par une instance d’EntityManager est définit par une unité persistante. Cette unité définit l’ensemble des classes qui sont liées à l’application et qui peuvent être liées au sein d’un même mapping dans une même base de données.

Voici les méthodes les plus utilisées concernant cette interface :
  • persist : permet de persister une instance d’une entité
  • merge : permet de sauvegarder les modifications faites concernant une entité dans le contexte
  • remove : permet de supprimer une instance d’une entité
  • find : permet de récupérer une entité en fonction de sa clé primaire
  • refresh : permet de réinitialiser l’état d’un objet par rapport à la base de données (annule toute modification)
  • createQuery : méthode retournant un objet Query permettant d’effectuer des requêtes plus spécialisées
          1. Gestion du cycle de vie d’une entité

Nous allons décrire, dans cette section, les opérations liées à la gestion du cycle de vie des entités. Une instance peut avoir l’état de : nouveau, gérée, détachée ou supprimée.

  • Une nouvelle instance n’a pas d’identité persistante, elle n’est pas encore associée au contexte de persistance.
  • Une instance gérée est une instance avec une identité persistante, elle est associée avec un contexte persistant.
  • Une instance détachée est une instance ayant une identité persistante mais qui n’est plus liée au contexte de persistance.
  • Une instance supprimée est une instance ayant une identité persistante, associée avec le contexte de persistance mais qui est programmée pour être supprimée de la base de données.
            1. Persister une instance d’une entité

Une nouvelle instance d’entité devient persistante et gérée lorsque l’on invoke la méthode persist avec l’instance en paramètre ou lorsque cette opération est effectuée en cascade.
Voici quelques détails concernant cette opération (E est une entité) :
  • Si E est une nouvelle entité, elle passe à l’état gérée. L’entité E sera ajoutée en base de données avant que la transaction soit commitée ou lorsque que la méthode flush est appelée.
  • Si E est une entité préexistante, elle est ignorée par l’opération de persistance. Cependant l’opération est de type « cascade » sur l’ensemble des entités référencées par E, si les relations de E vers d’autres entités sont marquées avec cascade=PERSIST ou cascade=ALL (nous verrons plus tard l’ensemble des différentes annotations)
  • Si E est une entité supprimée, elle passe en état : « gérée »
  • Si E est détachée, alors une exception de type IllegaleArgumentException est lancée
            1. Supprimer une instance

Vous pouvez supprimer une entité en appelant la méthode remove de l’EntityManager et en lui passant l’entité à supprimer, ou alors l’entité peut être supprimée par « cascade ».
Voici quelques détails concernant cette opération (E est une entité) :
  • Si E est une nouvelle entité, l’opération est ignorée. Cependant l’opération de suppression est de type « cascade » sur l’ensemble des entités référencées par E, si les relations sur ces autres entités sont marquées comme cascade=REMOVE ou cascade=ALL.
  • Si E est détachée, alors une exception de type IllegaleArgumentException est lancée
  • Si E est supprimée, elle est ignorée par cette opération
            1. Synchronisation avec la base de données

Cette opération met à jour l’état d’un bean par rapport aux valeurs de la base de données. Cette synchronisation écrit l’ensemble des modifications des entités persistantes et de leurs relations.
Le fournisseur de persistance est permit d’effectuer une synchronisation vers la base de données à d’autres moment, comme par exemple avant l’exécution d’une requête. La méthode flush permet de forcer une synchronisation.
Cette synchronisation est appliquée aux entités associées au contexte de persistence. Il existe l’annotation FlushMode qui vous permet de spécifier de façon plus détaillée l’opération de synchronisation.
Voici quelques détails concernant cette opération (E est une entité) :
  • Si E est une instance ayant l’état gérée, elle est synchronisée avec la base de donnés
    • Pour toutes les entités Y référencées par E, si la relation entre ces deux entités est annotée : cascade=PERSIST ou cascade=ALL, l’opération de persistance est appliquée à Y.
    • Pour toutes les entités Y référencées par E, si la relation entre ces deux entités n’est pas annotée : cascade=PERSIST ou cascade=ALL :
      • Si Y est nouveau, une exception IllegaleStateException est jetée et la transaction est « rolled back ».
      • Si Y est détaché, cela dépend du type de relation qu’il y a entre Y et E. Si E connaît la relation, aucune modification est effectuée par rapport à la relation.Si Y connaît la relation, le comportement est indéfinit.
  • Si E est supprimée, l’entité est supprimée de la base de données. Aucune opération de « cascade » n’est lancée.
            1. Entités détachées

Lorsque le contexte de persistance est stoppé, toutes les entités rattachées à ce contexte sont détachées.
L’application doit alors accéder avec prudence aux propriétés de ces objets.
Voici les états sur lesquels il faut faire attention :
  • Les champs persistants marqués par : fetch=LAZY

Les instances détachées continuent de vivre à l’extérieur du contexte de persistance et leur état n’est plus guaranti d’être mis à jour avec la base de données.

Une entité détachée peut simplement être le résultat d’une sérialisation d’une entité ou lorsque vous le passer à un autre tiers de votre application (une remote interface par exemple). Dans ce cas, les mêmes règles s’appliquent.
            1. « Merge » opération

L’opération « merging » vous permet de propager l’état « détaché » d’une entité vers l’état persistant grâce à l’EntityManager.
Voici quelques détails concernant cette opération (E est une entité) :
  • Si E est une instance détachée, elle est copiée dans une instance « gérée » E’ préexistante de la même entité ou alors une nouvelle instance de E est créée.
  • Si E est une nouvelle instance, une nouvelle instance « gérée » E’ est créée et l’état de E est copié dans E’.
  • Si E est une instance supprimée, une IllegaleArgumentException est jetée.

            1. Exemple d’utilisation

//TODO

import java.util.Collection;

import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import com.society.stockmanager3.entities.beans.City;
import com.society.stockmanager3.entities.beans.Country;
import com.society.stockmanager3.exceptions.NotFindException;
import com.society.stockmanager3.sessions.interfaces.LocalStorage;
import com.society.stockmanager3.sessions.interfaces.RemoteStorage;

@Stateless
public class StorageBean implements RemoteStorage, LocalStorage {

// Injection
@PersistenceContext(unitName = "stockManager")
protected EntityManager em;

public StorageBean() {
}

public Collection<Country> getAllCountry() {
return em.createQuery("from Country c").getResultList();
}

public void addCountry(Integer countryId, String name) {
Country country = new Country();
country.setId(countryId);
country.setName(name);
em.persist(country);
}

public void removeCountry(Integer countryId) {
em.remove(em.find(Country.class, countryId));
}

public void addCity(Integer cityId, String name, Integer countryId) {
City city = new City();
city.setCountry(em.find(Country.class, countryId));
city.setId(cityId);
city.setName(name);
em.persist(city);
}

public void removeCity(Integer cityId) {
em.remove(em.find(City.class, cityId));
}
}


2.3.5.Message Driven Bean (MDB)

        1. Business Interface

L’interface à utiliser, est bien entendu, l’interface définit par JMS (Java Message Service), c'est-à-dire javax.jms.MessageListener.
Cette interface peut dépendre du type de messagerie sur laquelle vous voulez connecter votre bean (c’est généralement JMS).

Il existe cependant un nouveau type de Message Driven Bean, ce sont les Message Driven Bean POJOs. Ce type permet d’interconnecter un client avec un MDB et de permettre à ce client de faire de l’appel de méthode à distance via JMS.
Ce type d’utilisation se rapproche des Session bean. Cependant la connexion se fait alors par message JMS et non via RMI.
De plus les appels et la réception de résultat sont asynchrones.
        1. Bean Class

Vous devez simplement annoter votre classe avec @MessageDriven. Votre classe doit également implémenter la méthode onMessage(Message msg) dans le cas d’une utilisation directe avec JMS.

Il vous faut également définir les différents paramètres à utiliser pour la connexion à la destination …
Pour cela on utilisera les propriétés : destinationType et destination.
Voici un exemple de paramétrage d’un bean :

@MessageDriven(activateConfig =
{
@ActivationConfigProperty(propertyName="destinationType",
propertyValue="javax.jms.Queue"),
@ActivationConfigProperty(propertyName="destination",
propertyValue="queue/mdb")
})

Cette annotation est bien entendu à utiliser sur la classe d’implémentation du bean.
        1. Exemple

//TODO

import javax.annotation.Resource;
import javax.ejb.ActivationConfigProperty;
import javax.ejb.MessageDriven;
import javax.ejb.MessageDrivenContext;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;

@MessageDriven(activateConfig =
{
@ActivationConfigProperty(propertyName="destinationType",
propertyValue="javax.jms.Queue"),
@ActivationConfigProperty(propertyName="destination",
propertyValue="queue/simpleQueue")
})
public class SimpleMessageBean implements MessageListener {

@Resource MessageDrivenContext mdc;

public void onMessage(Message inMessage) {
TextMessage msg = null;

try {
if (inMessage instanceof TextMessage) {
msg = (TextMessage) inMessage;
System.out.println
("MESSAGE BEAN: Message received: "
+ msg.getText());
} else {
System.out.println
("Message of wrong type: "
+ inMessage.getClass().getName());
}
} catch (JMSException e) {
e.printStackTrace();
mdc.setRollbackOnly();
} catch (Throwable te) {
te.printStackTrace();
}
}
}



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 

Retrouvez ci-dessous les autres sections du Laboratoire Sun
Exemples de code
JavaManipuler les looks and feel (lister et affecter)10/15/07
JavaFaire sa propre injection de dépendance avec les annotations5/9/06
JavaSplash screen avec progress Bar5/5/06
JavaFaire un splash screen en swing5/5/06

Essentiels de cours Java
JavaEJB 3 - Les Entreprise Java Bean version 3 (JavaBeans)
Cet essentiel est la suite de « Entreprise JavaBean 2.1 ». Cependant, nous allons étudier les nouvelles spécifications 3.0 qui simplifient énormément le développement par rapport aux EJB 2.6/20/06
JavaSWT - Créer des interfaces graphiques performantes
SWT (Standard Widget Toolkit) est une librairie graphique qui vous permet de réaliser des applications graphiques Java beaucoup plus avancées et surtout plus rapide à l’exécution.1/29/06
JavaStruts - Un framework MVC pour vos applications J2EE
Struts est un framework open-source qui vous permet de gagner du temps, mais qui permet aussi de voir des applications complexes comme une suite de composants de base : Vues, Actions, Modèles. Vous gagnez ainsi en évolutivité et en lisibilité du code.1/13/06
JavaHibernate - Persistance objet - relationnel
Cet essentiel explique comment utiliser Hibernate afin de gérer la persistance objet relationnel au sein de vos applications Java.12/14/05
JavaIntroduction J2EE - Applications d'entreprise
Cours d'introduction aux diverses technologies et outils que l'on peut rencontrer dans le monde du Java orienté entreprise J2EE12/14/05
JavaEJB 2 - Les Entreprise Java Bean (JavaBeans)
L'objectif avec EJB2 (Entreprise JavaBeans) est d'introduire les concepts de l’Ingénierie Logicielle Basée sur les Composants.12/14/05
JavaDesign Pattern - Améliorez l'architecture de vos programmes
Afin de répondre a des situation récurrentes en programmation, les "design pattern" apportent une solution type à beaucoup de contraintes liées à la programmation objet.12/14/05
JavaArchitecture J2EE - Comment organiser son application J2EE
Ce cours explique comment créer un code modulable, lisible et évolutif afin d'assurer la pérénité de son application.12/14/05
JavaLes web-services - Publication de services
Le développement tend vers les technologies du Web. Il est difficile de faire la distinction entre les différents logiciels qui sont de plus en plus intégrés au Web. Les Web Services rentrent dans l’optique de différencier bien précisément les couches.12/14/05
JavaAnt - L'automatisation des tâches du programmeur
Ecrire des scripts afin d'exécuter les tâches récurrentes10/31/05
JavaIntroduction au langage Java - Présentation & historique
Présentation des origines du langage, ainsi que se buts premiers8/11/05
JavaLa Syntaxe Java - Bases & nomenclatures
Bases de la syntaxe du langage Java8/11/05
JavaLes Classes - Concepts & héritage
Base du développement objet en Java grâce aux classes8/11/05
JavaLes Exceptions - Gestion d'erreurs
Gérer les erreurs liés à la programmation8/11/05

Articles
Eclipse Europa : le successeur de Callisto
Après Eclipse Callisto (Eclipse 3.2), la fondation Eclipse sort la nouvelle mouture d'Eclipse appelée Europa (Eclipse 3.3) faisant ainsi passer le nombre de projets embarqués de 10 à 21. Que ceux qui sont réticents aux « distributions » d'Eclipse se rassu12/21/07
JavaCruiseControl : l’outil d’intégration continue à avoir dans sa boite à outils
CruiseControl est un projet open-source offrant de multiples fonctionnalités pour l’intégration, que ce soit pour des développements Java ou .Net. Il est courant sur un projet d’être plusieurs développeurs avec des tâches de développement réparties. Dans7/2/07
JavaEJB3 - Des concepts à l'écriture du code - Editions DUNOD
Consulter le résumé du premier ouvrage du laboratoire Sun de SUPINFO : EJB3 - Des concepts à l'écriture du code. Guide du développeur, éditions DUNOD.5/27/07
JavaPassage de certification Java Web (SCWCD)
Passer une certification est toujours un moment important car cela permet de mieux faire reconnaître ses compétences face à un recruteur ou un employeur.5/12/07
JavaGoogle Web Toolkit
Google Web Toolkit est un framework java pour générer du javascript et des requêtes Ajax à partir d’un code java. Voilà comment il fonctionne.5/10/07
JavaJ2ME Vs SDE
Demain, les terminaux « légers » seront plus nombreux que les ordinateurs personnels, ce qui entraîne une bataille sur le choix d’une plateforme identique à tous ces terminaux… Aujourd’hui nous retrouvons le J2ME ainsi que le SDE qui s’offrent une rude b4/22/07

Tips du laboratoire
EclipseVisual Editor avec Eclipse Europa, c'est possible3/28/08
EclipseGérer les projets dans un workspace.10/16/07
JavaManager votre server d'application avec Eclipse4/21/07
JavaVue des sub-packages avec Eclipse4/21/07
JavaGlisser-déposer avec Eclipse4/21/07