Exercice 2 : Un bean d'entité simple

[<<Retour] [Sommaire] [Suivant>>]

Cet exercice étend l'exemple de l'exercice 1 pour utiliser un bean d'entité. BonusServlet appelle le bean d'entité pour enregistrer et retrouver le numéro de sécurité sociale dans une table de base de donnéé. Cette fonctionnalité d'accès à une base de donnée ajoute le quatrième et dernier tiers à notre exemple d'architecture client léger multi-tiers débuté dans l'exercice 1.

Le J2EE SDK est livré avec une base de données Cloudscape, et vous n'avez pas besoin de réglages supplémentaires dans votre environnement pour que le bean d'entité puisse accéder à la base. En fait dans cet exemple, vous n'aurez pas à écrire de code SQL ou JDBC pour créer la base de donnée ou effectuer les opérations d'accès à la base de donnée. La table est crée et le code SQL est généré par la Deployment tool pendant l'assemblage et le déploiement. L'exercice 7 Technologie JDBC et persistance géréé par le bean montre comment écrire le code SQL pour un bean d'entité.

Créer le bean d'entité

Un bean d'entité représente des données persistantes stockées dans une ligne de table de base de données. Quand un bean d'entité est crée, les données sont écrites dans la table de base de données appropriée, et si les données d'un bean d'entité sont modifiées, les données dans la ligne de la table de base de donnée sont aussi modifiées. La création de la table dans la base de donnée et les mises à jour de ligne interviennent toutes sans que vous ayez à écrire la moindre ligne de code SQL ou JDBC.

Les données d'un bean d'entité sont persistantes car elles surivivent à un plantage.

BonusHome

La principale différence entre le bean de session CalcHome de l'exercice 1 et le bean d'entité BonusHome de cette exercice (voir plus bas) est la méthode findByPrimaryKey . Cette méthode de recherche prend une clé primaire comme paramètre. Dans cet exemple, la clé primaire est un numéro de sécurité sociale, qui est utilisé pour retrouver une ligne de table de base de donnée correspondant au numéro de sécurité sociale passé à la méthode.

La méthode create prend une valeur de bonus et une clé primaire comme paramètre. Quand la BonusServlet instantie l'interface home et appelle sa méthode create, le conteneur crée un instance de BonusBean et appelle sa méthode ejbCreate . Les méthodes BonusHome.create et BonusBean.ejbCreate doivent avoir les mêmes signatures, pour que les valeurs du bonus et de la clé primaire puissent être passées de l'interface home au bean d'entité par le conteneur du bean d'entité. Si la ligne pour un numéro donné de clé primaire (sécurité sociale) existe déjà, une java.rmi.RemoteException est déclenchée qui est captée par le code client de la BonusServlet.

package Beans;

import java.rmi.RemoteException;
import javax.ejb.CreateException;
import javax.ejb.FinderException;
import javax.ejb.EJBHome;

public interface BonusHome extends EJBHome {
  public Bonus create(double bonus, String socsec)
        throws CreateException, RemoteException;
  public Bonus findByPrimaryKey(String socsec)
        throws FinderException, RemoteException;
}

Bonus

Après que l'interface home soit crée, le container crée l'interface remote et le bean d'entité. L'interface Bonus déclare les méthodes getBonus et getSocSec pour que la servlet puisse accéder aux données du bean d'entité.

package Beans;

import javax.ejb.EJBObject;
import java.rmi.RemoteException;

public interface Bonus extends EJBObject {
  public double getBonus() throws RemoteException;
  public String getSocSec() throws RemoteException;
}

 

BonusBean

BonusBean est un bean d'entié géré par le conteneur. Cela veut dire que le conteneur s'occupe de la persistance des données et de la gestion des transactions sans que vous ayez à écrire le code pour le transfert des données entre le bean d'entité et la base de données ou pour définir les limites des transactions.

Si pour une raison ou une autre vous souhaitez que votre bean d'entité gére lui-même sa persistance ou ses transactions, vous pouvez fournir des implémentations pour quelques unes des méthodes vides de BonusBean ci après. Les liens suivants vous emménent sur des documents qui présentent la persistance et les transactions gérées par le bean.

Quand BonusServlet appelle BonusHome.create , le container appelle la méthode BonusBean.setEntityContext. L'instance d'EntityContext passée à la méthode setEntityContext a des méthodes qui permettent à votre bean de renvoyer une référence de lui-même ou d'obtenir sa clé primaire.

Après, le conteneur appelle la méthode ejbCreate . La méthode ejbCreate assigne des valeurs aux variables de l'instance du bean, puis enregistre ces données dans la base de données. La méthode ejbPostCreate est appelée après la méthode ejbCreate et exécute toutes les traitements requis après la création du bean. Cet exemple simple ne nécessite pas de traitement de postcréation.

Les autres méthodes vides sont des appels de fonctions utilisés par le conteneur pour notifier au bean qu'un événement est arrivé. Vous pouvez fournir un comportement pour certaines de ces méthodes si vous utilisez la persistance gérée par le bean, et d'autres si vous avez besoin de fournir des spécifications précises pour la maintenance ou l'initialisation du bean. Ces opération de maintenance - nettoyage et initialisations prennent place à des moments précis du cycle de vie du bean, et le conteneur prévient et déclenche les méthodes nécessaires au moment opportun. Voici une brève explication de ces méthodes:

Les méthodes getBonus et getSocSec sont appelées par les clients pour accéder aux données stockées dans les variables de l'instance. Cet exemple n'a pas de méthode set< type > , mais si c'était le cas, les clients pourraient les appeler pour modifier les données dans les propriétés (variables) de l'instance. Tout changement dans les propriétés de l'instance résulte en une mise à jour de la ligne de table de base de données correspondante.

package Beans;

import java.rmi.RemoteException;
import javax.ejb.CreateException;
import javax.ejb.EntityBean;
import javax.ejb.EntityContext;

public class BonusBean implements EntityBean {

  public double bonus;
  public String socsec;
  private EntityContext ctx;

  public double getBonus() {
    return this.bonus;
  }
  public String getSocSec() {
    return this.socsec;
  }

  public String ejbCreate(double bonus, 
  String socsec) 
  throws CreateException{
  //Appelé par le conteneur après setEntityContext 
    this.socsec=socsec;
    this.bonus=bonus;
     return null;
  }

  public void ejbPostCreate(double bonus,
                            String socsec) {
  //Appelé par le conteneur après ejbCreate
  }

//Les méthodes suivantes sont des appels de fonctions
//appelés par le conteneur pour avertir
//le bean qu'un événement à eu lieu

  public void ejbActivate() {
  //Appelé par le conteneur avant que le Bean 
  //rentre en mémoire
  }

  public void ejbPassivate() {
  //Appelé par le conteneur avant que le bean
  //soit stocké
  }

  public void ejbRemove() throws RemoteException {
  //Appelé par le conteneur avant que
  //les données soit supprimées de la base de données
  }

  public void ejbLoad() {
  //Appelé par le conteneur
  //pour rafraîchir l'éatat du bean d'entité
  }

  public void ejbStore() {
  //Appelé par le conteneur
  //pour sauver l'état du bean dans la base de données
  }

  public void setEntityContext(EntityContext ctx){
  //Appelé par le conteneur pour définir le contexte du Bean
  }

  public void unsetEntityContext(){
  //Appelé par le conteneur pour enlever le contexte du Bean
  }
}

Modifier la Servlet

Le code de la BonusServlet pour cette exercice est très similaire à celui de l'exercice 1 avec des modifications dans les méthodesinit et doGet . La méthode init pour cet exercice utilise à la fois le bean de session CalcBean, et le bean d'entité BonusBean .

public class BonusServlet extends HttpServlet {
  CalcHome homecalc;
  BonusHome homebonus;
  Bonus theBonus, record;

public void init(ServletConfig config) 
  throws ServletException{
  try {
    InitialContext ctx = new InitialContext();
    Object objref = ctx.lookup("bonus");
    Object objref2 = ctx.lookup("calcs");
    homebonus=(
          BonusHome)PortableRemoteObject.narrow(
          objref, BonusHome.class);
    homecalc=(CalcHome)
          PortableRemoteObject.narrow(
          objref2, CalcHome.class);
  } catch (Exception NamingException) {
    NamingException.printStackTrace();
  }
}

La clause try dans la méthode doGet crée des interfaces home pour des CalcBean et BonusBean . Après avoir appelé calcBonus pour calculer le bonus, la méthode BonusHome.create est appelée pour créer une instance de bean d'entité et la ligne correspondante dans la table de la base de données sous-jacente. Après la création de la table, la méthode BonusHome.findByPrimaryKey est appelée pour obtenir le même enregistrement par sa clé primaire (numéro de sécurité sociale). Après, une page HTML est renvoyée au navigateur web avec les données transmises initialement, le bonus calculé, et les données reçues de la base de données.

La clause catch intercepte et traite les clés primaires (numéro de sécurité sociale) multiples. La base de donnée ne peut avoir deux lignes avec la même clé primaire, c'est pourquoi si vous passez deux fois le même numéro de sécurité sociale à la servlet, la servlet intercepte et traite l'erreur avant de créer le bean d'entité. Dans le cas d'une clé multiple (duplicate key), la servlet renvoit une page HTML avec les données passées à l'origine, le bonus calculé et un message d'erreur.

try {
    Calc theCalculation; 
//Récupérer les informations de bonus et numéro de sécurité
    String strMult = request.getParameter(
                 "MULTIPLIER");//Calculer le bonus
    Integer integerMult = new Integer(strMult);
    multiplier = integerMult.intValue();
    socsec = request.getParameter("SOCSEC");
//Calculer le bonus
    double bonus = 100.00;
    theCalculation = homecalc.create();
    calc = theCalculation.calcBonus(
         multiplier, bonus);
//Créer une ligne dans la table
    theBonus = homebonus.create(calc, socsec);
    record = homebonus.findByPrimaryKey(socsec);
//Afficher les données
    out.println("<H1>Bonus Calculation</H1>");
    out.println("<P>Soc Sec passed in: " + 
        theBonus.getSocSec() + "<P>");
    out.println("<P>Multiplier passed in: " + 
        multiplier + "<P>");
    out.println("<P>Bonus Amount calculated: " + 
   theBonus.getBonus() + "<P>");
    out.println("<P>Soc Sec retrieved: " + 
    record.getSocSec() + "<P>");
    out.println("<P>Bonus Amount retrieved: " + 
   record.getBonus() + "<P>");
    out.println("</BODY></HTML>");
//Intercepter le message d'erreur sur les clés dupliquées
  } catch (javax.ejb.DuplicateKeyException e) {
    String message = e.getMessage();
//Afficher les données
    out.println("<H1>Bonus Calculation</H1>");
    out.println("<P>Soc Sec passed in: " + 
    socsec + "<P>");
    out.println("<P>Multiplier passed in: " + 
        multiplier + "<P>");
    out.println("<P>Bonus Amount calculated: " + 
    calc + "<P>");
    out.println("<P>" + message + "<P>");
    out.println("</BODY></HTML>");
  } catch (Exception CreateException) {
    CreateException.printStackTrace();
  }
}

Compiler

Tout d'abord, compiler le bean d'entité et la servlet. Se reporter à l'exercice 1 pour le paramétrage du PATH et du CLASSPATH et les informations sur l'endroit où placer les fichiers sources.

Compiler le bean d'entité

Unix

#!/bin/sh
cd /net/home/lmaitre/J2EE
J2EE_HOME=/net/home/lmaitre/J2EE/j2eesdk1.3
CPATH=.:$J2EE_HOME/lib/j2ee.jar
javac -d . -classpath "$CPATH" Beans/BonusBean.java
           Beans/BonusHome.java Beans/Bonus.java

Windows

cd \home\monicap\J2EE
set J2EE_HOME=\home\monicap\J2EE\j2eesdk1.3
set CPATH=.;%J2EE_HOME%\lib\j2ee.jar
javac -d . -classpath %CPATH% Beans/BonusBean.java 
           Bean s/BonusHome.java Beans/Bonus.java

Compiler la Servlet

Unix:

cd /net/home/lmaitre/J2EE/ClientCode 
J2EE_HOME=/net/home/lmaitre/J2EE/j2eesdk1.3
CPATH=.:$J2EE_HOME/lib/j2ee.jar:/net/home/lmaitre/J2EE
javac -d . -classpath "$CPATH" BonusServlet.java 

Windows:

cd \home\monicap\J2EE\ClientCode
set J2EE_HOME=\home\monicap\J2EE\j2eesdk1.3
set CPATH=.;%J2EE_HOME%\lib\j2ee.jar;
          \home\monicap\J2EE
javac -d . -classpath %CPATH% BonusServlet.java

Démarrer les serveurs et les outils

Pour exécuter cet exemple vous avez besoin de démarrer le serveur J2EE, l'outil de déploiement et la base de donnée Cloudscape. Dans des fenêtres différentes, tapez les commandes suivantes :

j2ee -verbose
deploytool
cloudscape -start

Si cela ne marche pas, tapez ceci à partir du répertoire J2EE :

Unix

j2eesdk1.3/bin/j2ee -verbose
j2eesdk1.3/bin/deploytool
j2eesdk1.3/bin/cloudscape -start

Windows

j2eesdk1.3\bin\j2ee -verbose
j2eesdk1.3\bin\deploytool
j2eesdk1.3\bin\cloudscape -start

Assembler et déployer

Les étapes de cette sections sont :

Mise à jour du fichier d'application

Le fichier web archive (WAR) contient BonusServlet et bonus.html . Comme vous avez changé BonusServlet , vous devez mettre à jour l'application J2EE avec le nouveau code de la servlet.

Note: L'application BonusApp de la leçon précédente est automatiquement désinstallée

Création du bean d'entité

Les étapes pour créer le fichier JAR de l'EJB sont très ressemblantes aux étapes pour le bean de session vues dans l'exercice 1. Il y a quelques différences cependant et ces différences sont expliquées ici.

Note: Dans cet exercice le bean d'entité va dans un fichier JAR différent de celui du bean de session de l'exercice 1 pour continuer l'exemple de l'exercice 1 avec le minimum de changements. Comme ces beans ont des fonctionnalités liées on devrait pourtant les livrer et les déployer dans le même fichier JAR. Vous verrez comment livrer des beans liès dans le même fichier JAR dans l'exercice 3.

Menu File :

Introduction :

EJB JAR :

Edit Contents of BonusJar:

 

Ajout de classes à BonusJar

EJB JAR :

General :

Entity Settings:

Environment Entries:

Enterprise Bean References:

Resource References:

Security:

Transaction Management :

 

Gestion des transactions

Vue File :

Avant que l'application J2EE puissent être déployée, vous avez besoin de préciser les paramètres de déploiement pour le bean d'entité et générer le SQL. Voici comment faire :

Vue File :

Fenêtre Inspecting :

Deployment Settings:

Note: Si vous obtenez une erreur indiquant que la connexion a été refusée, démarrer la base de donnée comme indiqué dans Démarrer les serveurs et les outils.

 

Génération du SQL et de la table de base donnée

Vérification et déploiement de l'application J2EE

Vérification:

Note: Daans la version 1.2 du J2EE SDK vous pouvez avoir une erreur tests app.WebURI . L'application J2EE se déploiera malgré cela.

Déploiement:

Note: Ne pas cocher la case Return Client Jar. La seule raison de cocher cette case est quand vous voulez utiliser la persistance gérée par le bean ou déploer une application autonome comme programme client. Cet exemple utilise une servlet et une âge HTMl donc ces cases ne doivent pas être cochées. Cocher ces cases crée un fichier JAR avec les informations de déploiement nécessaires pour une application autonome.

Exécuter l'application J2EE

Le serveur web s'exécute sur le port 8000 par défaut. Pour ouvrir la page bonus.html aller avec votre navigateur à l'adresse http://localhost:8000/BonusRoot/bonus.html , qui est l'endroit où la Deployment tool à mis le fichier HTML.

Saisir un numéro de sécurité sociale et un multiplicateur et cliquer sur le bouton Submit . BonusServlet traite vos données et renvoie une page HTML avec le résultat du calcul du bonnus.

Bonus Calculation

Soc Sec passed in: 777777777
Multiplier passed in: 25
Bonus Amount calculated: 2500.0
Soc Sec retrieved: 7777777777
Bonus Amount retrieved: 2500.0

Si vous retournez sur bonus.html et changez le multiplicateur en 2 mais utilisez le même numéro de sécurité sociale, vous obtenez ceci :

Bonus Calculation
Soc Sec passed in: 777777777
Multiplier passed in: 2
Bonus Amount calculated: 200.0
Duplicate primary key.

[TOP]