TD – TME 5 TD

Transcription

TD – TME 5 TD
M1 – STL ­ Composants
UPMC
Février­Juin 2007
TD – TME 5
Description de
Fo r t u n e O f T h e D a y, a p p l i c a t i o n
simple réalisée à l'aide d'EJB
TD
L'objet de l'application FortuneOfTheDay est de retourner à chaque appel de son unique méthode métier une message composé de "hello !" suivi d'un dicton pris au hasard dans une base de données des dictons. L'application fait appel à deux beans et une base de données, un bean session nommé "Hello", un bean entity nommé "Fortune". On utilisera la base de données intégrée à Jboss nommée hsql. On placera les sources des fichiers dans un package nommé «
fortune » .
Le serveur d'application utilisé est Jboss. Le répertoire bin de l'installation de Jboss contient les scripts pour lancer et arrêter le serveur (run et shutdown). Par ailleurs, on travaillera avec la configuration "default" du serveur, c'est à dire celle qui correspond au répertoire " server/default
" de l'installation de JBoss.
1. L'ENTITY BEAN FORTUNE
La base de données de dictons comporte trois champs :
– l'index du dicton : "fortuneId" : un entier,
– le type du dicton : "type" : le dicton peut être du "matin" ou de l'"aprèsmidi", une chaine de caractères,
– le texte du dicton : "text" : une chaine de caractère
Interface de Bean
On a l'interface de bean suivante :
package fortune;
­ 1/21 ­
M1 – STL ­ Composants
UPMC
Février­Juin 2007
public interface Fortune extends EJBObject
{
public Integer getFortuneId() throws RemoteException;
public String getType() throws RemoteException;
public String getText() throws RemoteException;
}
Il faut noter que il s'agit d'une interface distante, destinée à être utilisée par un client distant, toutefois le bean session Hello se trouve sur le même serveur que l'entity bean on peut donc définir ce qu'on nomme une interface locale.
public interface FortuneLocal extends EJBLocalObject
{
public Integer getFortuneId();
public String getType();
public String getText();
}
elle ne diffère de l'interface distante que par son ancêtre EJBLocalObject et l'absence de RemoteException, elle ne pourra être accédée que depuis l'intérieur du serveur. L'interface distante pourra servir à faire des tests à distance.
Interface de Home Bean :
L'interface Home du bean, propose les méthodes qui permettent de le créer et de le retrouver. Elles sont l'équivalent d'un ajout d'une ligne dans la base de données et de méthodes de sélection dans celle­ci.
public interface FortuneHome extends EJBHome
{
public Fortune create(Integer fortuneId, String type, String text) throws CreateException,
RemoteException;
}
public Fortune findByPrimaryKey(Integer fortuneId) throws FinderException, RemoteException;
public Collection findByType (String type) throws FinderException, RemoteException;
public Collection findAll() throws FinderException, RemoteException;
La méthode de création du bean prend en argument les trois champs de la base de données. On a défini trois méthodes de sélection des enregistrements :
– par index, elle retourne une interface Fortune, accessible donc à distance
– par "type", elle retourne un collection d'interfaces Fortune
– la sélection de tous les enregistrements qui retourne une collection de beans correspondant à ­ 2/21 ­
M1 – STL ­ Composants
UPMC
Février­Juin 2007
tous les enregistrements de la base de données.
Tout comme on a défini une interface FortuneLocal pour les accès locaux au bean Fortune (et donc à la base de données), on a besoin d'une interface Home locale pour accèder aux FortuneLocal, les beans locaux.
public interface FortuneLocalHome extends EJBLocalHome
{
public FortuneLocal create(Integer fortuneId, String type, String text) throws CreateException;
public FortuneLocal findByPrimaryKey(Integer fortuneId) throws FinderException;
public Collection findByType (String type) throws FinderException;
public Collection findAll() throws FinderException;
}
Là encore, l'interface ne diffère de sa version distante que par son parent et les exceptions RemoteException qui ont disparues.
L'implémentation du bean Fortune
L'implémentation du BeanFortune se fait dans la classe fortune bean :
public abstract class FortuneBean implements EntityBean
{
protected EntityContext ctx;
public abstract String getType ();
public abstract void setType (String type);
public abstract String getText ();
public abstract void setText (String text);
public abstract Integer getFortuneId();
public abstract void setFortuneId(Integer fortuneId);
public FortuneBean() {};
public void ejbActivate () {}
public void ejbPassivate () {}
public void ejbRemove ()
public void ejbLoad () {}
public void ejbStore () {}
{}
public void setEntityContext (EntityContext ctx)
{
System.out.println("setEntityContext() called");
this.ctx = ctx;
}
­ 3/21 ­
M1 – STL ­ Composants
UPMC
Février­Juin 2007
public void unsetEntityContext ()
{
System.out.println("unsetEntityContext() called");
this.ctx = null;
}
public Integer ejbCreate (Integer fortuneId, String type, String text) throws CreateException
{
System.out.println("ejbCreate() called");
setFortuneId (fortuneId);
setType (type);
setText (text);
}
return fortuneId;
public void ejbPostCreate (Integer fortuneId, String type, String text) {}
}
Dans l'implémentation de FortuneBean, on peut remarquer que les getter/setter des champs du bean sont abstraits (abstracts) ceci provient du fait qu'on va faire un Bean CMP.
Le fichier de description du bean
Pour que les fichiers fournis par l'utilisateur soient correctement utilisés par le serveur, il faut indiquer à ce dernier à quoi ils correspondent. Ceci est fait dans le fichier "ejb­jar.xml" :
<!DOCTYPE ejb­jar PUBLIC "­//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN" "http://java.sun.com/j2ee/dtds/ejb­jar_2_0.dtd">
<ejb­jar>
<enterprise­beans>
<entity>
<ejb­name>Fortune</ejb­name>
<home>fortune.FortuneHome</home>
<remote>fortune.Fortune</remote>
<local­home>fortune.FortuneLocalHome</local­home>
<local>fortune.FortuneLocal</local>
<ejb­class>fortune.FortuneBean</ejb­class>
<persistence­type>Container</persistence­type> <primkey­field>fortuneId</primkey­field>
<prim­key­class>java.lang.Integer</prim­key­class>
<reentrant>False</reentrant>
<cmp­version>2.x</cmp­version> <abstract­schema­name>Fortune</abstract­schema­name>
­ 4/21 ­
M1 – STL ­ Composants
UPMC
Février­Juin 2007
<cmp­field>
<field­name>fortuneId</field­name>
</cmp­field>
<cmp­field>
<field­name>type</field­name>
</cmp­field>
<cmp­field>
<field­name>text</field­name>
</cmp­field>
<query>
<query­method>
<method­name>findByPrimaryKey</method­name>
<method­params> <method­
param>java.lang.Integer</method­param>
</method­params>
</query­method>
<ejb­ql>
<![CDATA[SELECT OBJECT(a) FROM Fortune AS a WHERE a.fortuneId = ?1]]>
</ejb­ql> </query>
<query>
<query­method>
<method­name>findByType</method­name>
<method­params> <method­param>java.lang.String</method­param>
</method­params>
</query­method>
<ejb­ql>
<![CDATA[SELECT OBJECT(a) FROM Fortune AS a WHERE a.type = ?1]]>
</ejb­ql> </query>
<query>
<query­method>
<method­name>findAll</method­name>
<method­params></method­params>
</query­method>
<ejb­ql>
<![CDATA[SELECT OBJECT(a) FROM Fortune AS a]]>
</ejb­ql> ­ 5/21 ­
M1 – STL ­ Composants
UPMC
Février­Juin 2007
</query>
<assembly­descriptor>
<container­transaction>
<method>
<ejb­name>Fortune</ejb­name>
<method­intf>Remote</method­intf>
<method­name>*</method­name>
</method>
<trans­attribute>Required</trans­attribute>
</container­transaction>
</assembly­descriptor>
</entity>
</enterprise­beans>
</ejb­jar>
Le premier bloc définit l'utilisation des différents fichiers : "home, localhome" correspondent aux interfaces de factory, "local, remote" aux interfaces du bean, "ejb­class" est le fichier compilé de l'implémentation du bean. Le second bloc qui commence par "<persistence­type>" indique au serveur que c'est le container qui se charge de la persistence. Puis il donne le nom du champ qui sert d'index à la base, ainsi que le type de donnée qu'il contient. L'indication du numéro de version "2.x" des CMP est obligatoire. L'abstract schema name est le nom de la table de la base de données, celui ci sera utilisé dans la description des méthodes de sélection des enregistrements qui vont suivre.
Les <cmp­field> décrivent les champs du CMP et donc de la base de donnée. Enfin, les blocs query décrivent les méthodes de sélection, en donnant leur implémentation en langage ejb­ql, assez proche du sql.
Le dernier bloc <assembly> peut contenir entre autre la description des configurations de transactions nécessaires pour accéder aux champs de la base de données via l'entity bean.
Hiérarchie des fichiers
On pourra organiser les fichiers de la manière suivante :
­ 6/21 ­
M1 – STL ­ Composants
UPMC
Février­Juin 2007
HelloFortune
|___src
| |___fortune
| |________ Fortune.java
| |________ FortuneLocal.java
| |________ FortuneHome.java
| |________ FortuneLocalHome
| |________ FortuneBean.java
|
|_______META­INF
| |_________ ejb­jar.xml
|
|_______ build.xml
La base de données
Dans le cas de bean CMP, si on ne fait rien la base de données est générée par défaut par le serveur d'ejb. Néanmoins, il est possible de définir un ensemble de cibles ant pour gérer la base de données. Ainsi il est possible de la créer à partir du script suivant :
hsql­create­table.sql :
DROP TABLE fortune if exists;
CREATE TABLE fortune
(fortuneId INTEGER,
type VARCHAR,
text VARCHAR,
CONSTRAINT pk_fortune PRIMARY KEY (fortuneId)
);
Les fichiers sql peuvent prendre place dans l'arborescence de l'application dans un répertoire "sql" du même niveau que META­INF et «src».
HelloFortune
|________ src
|________ META­INF
|________ sql
Le script « hsql­create­table » est exécuté à l'aide de la cible ant suivante :
­ 7/21 ­
M1 – STL ­ Composants
UPMC
Février­Juin 2007
<target name="db­create­table">
<java classname="org.hsqldb.util.ScriptTool" fork="yes">
<arg value="­url"/>
<arg value="jdbc:hsqldb:hsql:"/>
<arg value="­database"/>
<arg value="//localhost:1701"/>
<arg value="­script"/>
<arg value="sql/hsql­create­table.sql"/>
<classpath refid="hsql.classpath"/>
</java>
</target>
Il faut noter que le serveur Jboss doit être lancé pour que l'exécution de la cible ant ait un effet.
La variable « hsql.classpath » est définie par :
<!­­ Hypersonic SQL classpath ­­>
<path id="hsql.classpath">
<pathelement location="${jboss}/server/default/lib/hsqldb.jar"/>
</path>
où ${jboss} est le chemin vers le répertoire d'installation de jboss. Cette variable est déclarée dans l'entête du fichier build.xml :
<project name="helloworld" default="execute">
<property name="src" value="${basedir}/src"/>
<property name="jboss" value="c:/programs/jboss­4.0.3sp1/"/>
<property name="build.dir" value="${basedir}/build"/>
<path id="classpath">
<fileset dir="${jboss}">
<include name="lib/**/*.jar"/>
<include name="server/default/lib/**/*.jar"/>
</fileset>
<pathelement location="${basedir}"/>
<pathelement location="${build.dir}"/>
</path>
....
On voit que la connexion à la base de données se fait sur le port 1701, il faut donc indiquer au serveur qu'on veut pouvoir se connecter à la base de données sur ce port. Dans le cas du serveur Jboss, il faut modifier le fichier de configuration : hsqldb­ds.xml du répertoire "deploy" du serveur "default". Il faut décommenter la partie suivante du XML :
<mbean code="org.jboss.jdbc.HypersonicDatabase" ­ 8/21 ­
M1 – STL ­ Composants
UPMC
Février­Juin 2007
name="jboss:service=Hypersonic">
<attribute name="Port">1701</attribute>
<attribute name="Silent">true</attribute>
<attribute name="Database">localDB</attribute>
<attribute name="Trace">false</attribute>
<attribute name="No_system_exit">true</attribute>
</mbean>
Il est ainsi aussi possible de la peupler à l'aide du script suivant :
hsql­insert.sql :
DELETE FROM fortune;
INSERT INTO fortune VALUES
(0, 'matin', 'un tu l as vaut, mieux que deux tu l auras ');
INSERT INTO fortune VALUES
(1, 'aprèsmidi', 'rien ne sert de courir, il faut partir à point');
INSERT INTO fortune VALUES
(2, 'aprèsmidi', 'pierre qui roule, n'amasse pas mousse');
et en utilisant la cible ant suivante :
<target name="db­insert">
<java classname="org.hsqldb.util.ScriptTool" fork="yes">
<arg value="­url"/>
<arg value="jdbc:hsqldb:hsql:"/>
<arg value="­database"/>
<arg value="//localhost:1701"/>
<arg value="­script"/>
<arg value="sql/insert.sql"/>
<classpath refid="hsql.classpath"/>
</java>
</target>
Un fois le serveur lancé, on crée ainsi et on peuple la base de données à l'aide des cibles : db­
create­table et db­insert.
Pour voir le contenu de la base de données on pourra utiliser le script suivant :
listFortune.sql :
SELECT * from fortune;
­ 9/21 ­
M1 – STL ­ Composants
UPMC
Février­Juin 2007
Le déploiement
Le déploiement nécessite de compiler les fichiers et de faire un jar contenant les fichiers compilés et le répertoire META­INF. Ainsi la compilation pourra être l'objet de la cible ant suivante :
<target name="compile">
<mkdir dir="${build.dir}" />
<javac srcdir="${src}" destdir="${build.dir}" debug="on">
<classpath refid="classpath"/>
<include name="**/*.java"/>
</javac>
</target>
avec les variables ${build.dir}et ${src} correctement initialisées.
La construction du fichier jar se fera par la cible ant suivante :
<target name="package-ejb" depends="compile">
<mkdir dir="jar" />
<delete file="jar/fortune.jar"/>
<jar jarfile="jar/fortune.jar">
<metainf dir="META-INF" includes="**/*.xml" />
<fileset dir="${build.dir}">
<include name="fortune/Hello.class"/>
<include name="fortune/HelloBean.class"/>
<include name="fortune/HelloHome.class"/>
<include name="fortune/Fortune*.class"/>
</fileset>
</jar>
</target>
Avec Jboss le déploiement d'une application consiste à la copier dans le répertoire deploy de la configuration de serveur dans laquelle on travail (ici "server/default"). On pourra donc utiliser les deux cibles suivantes pour déployer et retirer l'application HelloFortune :
<target name="deploy" depends="package-ejb">
<copy file="jar/fortune.jar" tofile="${jboss}/server/default/deploy/fortune.jar"/>
</target>
<target name="undeploy">
<delete file="${jboss}/server/default/deploy/fortune.jar"/>
</target>
Toutefois il faut ajouter un fichier de déploiement qui est propre au serveur. Dans le cas de Jboss, ce fichier se nomme "jboss.xml" et est placé au même endroit que l' "ejb­jar.xml". Il décrit le nommage jndi des beans. C'est à dire le nom sous lequel on pourra les demander au service jndi.
<!DOCTYPE
jboss
PUBLIC
"http://www.jboss.org/j2ee/dtd/jboss_4_0.dtd">
"-//JBoss//DTD
­ 10/21 ­
JBOSS
4.0//EN"
M1 – STL ­ Composants
UPMC
Février­Juin 2007
<jboss>
<enterprise-beans>
<entity>
<ejb-name>Fortune</ejb-name>
<jndi-name>Fortune</jndi-name>
<local-jndi-name>FortuneLocal</local-jndi-name>
</entity>
</enterprise-beans>
</jboss>
Le déploiement et le retrait de l'application peuvent se faire le serveur aussi bien démarré qu'arrêté.
Le test
Le test de la base de données pourra se faire à l'aide du main suivant :
public class HelloClient {
public static void main(String[] args) throws Exception {
/* Setup properties for JNDI initialization.
* These properties will be read-in from
* the command-line. */
Properties props = System.getProperties();
props.put(Context.PROVIDER_URL,"jnp://localhost:1099");
props.put(Context.INITIAL_CONTEXT_FACTORY,"org.jnp.interfaces.NamingContextFactory");
props.put(Context.URL_PKG_PREFIXES, "org.jboss.naming.client");
/* Obtain the JNDI initial context.
* The initial context is a starting point for
* connecting to a JNDI tree. We choose our JNDI
* driver, the network location of the server, etc
* by passing in the environment properties. */
Context ctx = new InitialContext(props);
/* Get a reference to the home object - the
* factory for Hello EJB Objects */
Object obj = ctx.lookup("Fortune");
/* Home objects are RMI-IIOP objects, and so
* they must be cast into RMI-IIOP objects
* using a special RMI-IIOP cast.
* See Appendix X for more details on this. */
FortuneHome
FortuneHome.class);
home
=
(FortuneHome)
­ 11/21 ­
javax.rmi.PortableRemoteObject.narrow(obj,
M1 – STL ­ Composants
UPMC
Février­Juin 2007
Collection c = home.findByType ("aprèsmidi");
System.out.println(c.size());
}
Ce fichier peut être placé avec les autres sources dans le répertoire src. On utilisera la cible ant suivante pour l'exécuter :
<!-- ================================== -->
<!-EXECUTE
-->
<!-- ================================== -->
<target name="execute">
<java classname="fortune.HelloClient"
classpathref="classpath"
fork="yes"
failonerror="yes">
</java>
</target>
2. LE SESSION BEAN HELLO
interface de Bean
Le bean Hello propose une seule fonction métier nommée "hello()" qui retourne un message construit à partir d'un choix au hasard dans la base de données. Ainsi l'interface du bean est la suivante :
public interface Hello extends javax.ejb.EJBObject {
/**
* The one method - hello - returns a greeting to the client.
*/
public String hello() throws java.rmi.RemoteException;
}
interface de Home Bean
Il faut encore définir l'interface HelloHome de la factory de bean Hello :
­ 12/21 ­
M1 – STL ­ Composants
UPMC
Février­Juin 2007
public interface HelloHome extends javax.ejb.EJBHome {
/*
* This method creates the EJB Object.
*
* @return The newly created EJB Object.
*/
Hello create() throws java.rmi.RemoteException,javax.ejb.CreateException;
}
implémentation du bean Hello
Les interfaces distantes et Home posées on peut écrire l'implémentation du bean Hello. Dans cette implémentation, il faut que pour chaque appel de la méthode « hello() » le bean choisisse un enregistrement au hasard dans la base de données. Pour ce faire, le bean possède en attribut une référence sur le Home local des entity beans Fortune. Il s'en sert pour appeler la méthode de sélection qui renvoie tous les enregistrements et en prend un au hasard.
public class HelloBean implements javax.ejb.SessionBean {
private SessionContext ctx;
private FortuneLocalHome fortuneLocalHome;
private Random rnd;
//
// EJB-required methods
//
public void ejbCreate() {
System.out.println("ejbCreate()");
Object obj = ctx.lookup("FortuneLocal");
fortuneLocalHome = (FortuneLocalHome)
FortuneLocalHome.class);
rnd = new Random();
}
javax.rmi.PortableRemoteObject.narrow(obj,
public void ejbRemove() {}
public void ejbActivate() {}
public void ejbPassivate() {}
public void setSessionContext(javax.ejb.SessionContext ctx) {
this.ctx = ctx;
}
//
// Business methods
//
public String hello() {
System.out.println("hello()");
Collection fortuneCollection = null;
FortuneLocal fortuneChoosen = null;
­ 13/21 ­
M1 – STL ­ Composants
try
{
UPMC
Février­Juin 2007
int choosen = 0;
Iterator it = null;
fortuneCollection = fortuneLocalHome.findAll();
choosen = rnd.nextInt(fortuneCollection.size());
it = fortuneCollection.iterator();
for (int i = 0; i < choosen; i++) it.next();
fortuneChoosen = (FortuneLocal) (it.next());
}
catch (Exception e)
{
e.printStackTrace ();
}
}
return ("Hello, World! : "+ fortuneChoosen.getText());
}
descripteurs du bean Hello
Au descripteur « ejb­jar.xml » il faut ajouter une partie concernant le session bean Hello :
<session>
<ejb-name>Hello</ejb-name>
<home>fortune.HelloHome</home>
<remote>fortune.Hello</remote>
<ejb-class>fortune.HelloBean</ejb-class>
<session-type>Stateless</session-type>
<transaction-type>Container</transaction-type>
</session>
Outre la spécification de l'interface distante (« remote ») et de la factory (« home »), l'ejb­jar définit le type de session bean (« stateless »), ainsi que le gestionnaire de transaction (« Container »).
Il faut aussi augmenter les associations de noms jndi dans le descripteur de déploiement propre à Jboss, « jboss.xml », de la manière suivante :
<session>
<ejb-name>Hello</ejb-name>
<jndi-name>Hello</jndi-name>
</session>
déploiement du session bean Hello
La compilation et le déploiement du bean Hello sont identiques à ceux du bean Fortune. Il ­ 14/21 ­
M1 – STL ­ Composants
UPMC
Février­Juin 2007
suffit de mettre à jour les cibles ant de compilation, paquetage et déploiement.
test
Le programme de test du bean Hello est à peu de choses près identique à celui du bean Fortune :
public class HelloClient {
public static void main(String[] args) throws Exception {
/* Setup properties for JNDI initialization.
* These properties will be read-in from
* the command-line. */
Properties props = System.getProperties();
props.put(Context.PROVIDER_URL,"jnp://localhost:1099");
props.put(Context.INITIAL_CONTEXT_FACTORY,"org.jnp.interfaces.NamingContextFactory");
props.put(Context.URL_PKG_PREFIXES, "org.jboss.naming.client");
/* Obtain the JNDI initial context.
* The initial context is a starting point for
* connecting to a JNDI tree. We choose our JNDI
* driver, the network location of the server, etc
* by passing in the environment properties. */
Context ctx = new InitialContext(props);
/* Get a reference to the home object - the
* factory for Hello EJB Objects */
Object obj = ctx.lookup("Hello");
/* Home objects are RMI-IIOP objects, and so
* they must be cast into RMI-IIOP objects
* using a special RMI-IIOP cast.
* See Appendix X for more details on this. */
HelloHome home = (HelloHome) javax.rmi.PortableRemoteObject.narrow(obj, HelloHome.class);
/* Use the factory to create the Hello EJB Object */
Hello hello = home.create();
/* Call the hello() method on the EJB object. The
* EJB object will delegate the call to the bean,
* receive the result, and return it to us.
* We then print the result to the screen. */
System.out.println(hello.hello());
/* Done with EJB Object, so remove it.
* The container will destroy the EJB object. */
­ 15/21 ­
M1 – STL ­ Composants
UPMC
Février­Juin 2007
hello.remove();
}
3. ENTITY BEAN CMP À CLÉ AUTO­GÉNÉRÉE
L'entity bean Fortune tel que décrit précédemment est tel que pour en créer une instance il faut passer à l'interface FortuneHome la valeur de la clé « fortuneId ». Or, quand l'application démarre avec une base de données contenant déjà des enregistrements, on n'a pas de moyen de savoir quelle est la prochaine valeur de clé valide. En effet, suite aux possibles ajouts et retraits d'éléments de la base, il ne suffit pas de considérer le nombre d'enregistrements et de l'incrémenter.
Il est possible d'obtenir que chaque entity bean soit initialisé à sa création à l'aide d'une clé automotiquement générée. Pour ce faire il faut modifier l'entity bean Fortune et ajouter un fichier de configuration aux fichiers ejb­jar.xml et jboss.xml.
modifications de l'entity bean Fortune :
Il n'est plus besoin de passer aux méthodes de création du bean Fortune la valeur de fortuneId. On modifie donc les interfaces FortuneHome et FortuneHomeLocal, ainsi que l'implémentation des méthodes de création de FortuneBean.
FortuneHome :
public interface FortuneHome extends EJBHome
{
...
public Fortune create(String type, String text) throws CreateException, RemoteException;
...
}
FortuneHomeLocal :
public interface FortuneLocalHome extends EJBLocalHome
{
...
public FortuneLocal create(String type, String text) throws CreateException;
...
}
FortuneBean ;
public abstract class FortuneBean implements EntityBean
{
­ 16/21 ­
M1 – STL ­ Composants
UPMC
Février­Juin 2007
...
public Integer ejbCreate (String type, String text) throws CreateException
{
System.out.println("ejbCreate() called");
setType (type);
setText (text);
return null;
}
public void ejbPostCreate (String type, String text) {}
...
}
modification du descripteur de déploiement :
Il faut indiquer dans le descripteur de déploiement que le champ fortuneId de la base est incrémenté automatiquement :
<!DOCTYPE ejb­jar PUBLIC "­//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN" "http://java.sun.com/j2ee/dtds/ejb­jar_2_0.dtd">
<ejb­jar>
<enterprise­beans>
<entity>
<ejb­name>Fortune</ejb­name>
<home>fortune.FortuneHome</home>
...
<cmp­field>
<field­name>fortuneId</field­name>
<auto­increment />
</cmp­field>
</entity>
...
</enterprise­bean>
</ejb­jar>
fichier de configuration du CMP de jBoss :
­ 17/21 ­
M1 – STL ­ Composants
UPMC
Février­Juin 2007
Il est nécessaire maintenant de décrire à jBoss le mapping à effectuer entre les champs de la base de données et les attributs de l'entity bean Fortune. Ceci est fait à l'aide du fichier jbosscmp­
jdbc.xml qui est placé dans l'arborescence des fichiers dans le même répertoire que les descripteurs de déploiement, le répertoire META­INF.
<?xml version="1.0" encoding="UTF­8"?>
<!DOCTYPE jbosscmp­jdbc PUBLIC
"­//JBoss//DTD JBOSSCMP­JDBC 4.0//EN"
"http://www.jboss.org/j2ee/dtd/jbosscmp­jdbc_4_0.dtd">
<!­================================================================= ­­>
<!­­ ­­>
<!­­ Standard JBossCMP­JDBC Configuration ­­
>
<!­­ ­­>
<!­­================================================================= ­­>
<!­­ $Id: standardjbosscmp­jdbc.xml,v 1.84.2.6 2005/01/26 18:51:35 starksm Exp $ ­­>
<jbosscmp­jdbc>
<enterprise­beans>
<entity>
<ejb­name>Fortune</ejb­name>
<datasource>java:/DefaultDS</datasource>
<datasource­mapping>Hypersonic SQL</datasource­mapping>
<create­table>true</create­table>
<remove­table>false</remove­table>
<table­name>Fortune</table­name>
<cmp­field>
<field­name>fortuneId</field­name>
<column­name>fortuneId</column­name>
<jdbc­type>INTEGER</jdbc­type>
<sql­type>INTEGER</sql­type>
<auto­increment />
</cmp­field>
<cmp­field>
<field­name>type</field­name>
<column­name>type</column­name>
<jdbc­type>VARCHAR</jdbc­type>
­ 18/21 ­
M1 – STL ­ Composants
UPMC
Février­Juin 2007
<sql­type>VARCHAR</sql­type>
</cmp­field>
<cmp­field>
<field­name>text</field­name>
<column­name>text</column­name>
<jdbc­type>VARCHAR</jdbc­type>
<sql­type>VARCHAR</sql­type>
</cmp­field>
<entity­command name="hsqldb­fetch­key" class="org.jboss.ejb.plugins.cmp.jdbc.keygen.JDBCHsqldbCreateCommand">
<attribute name="key­generator­factory">UUIDKeyGeneratorFactory</attribute> </entity­command>
</entity> </enterprise­beans> </jbosscmp­jdbc>
N.B. Base de donnée :
Dans le fichier décrit, la table de la base de données est automatiquement créée (clé « <create­table> »). On n'utilise plus le script de création de table. Si cette table existait auparavant dans la base de données un conflit peut se produire, il peut donc être utile de supprimer cette table. La suppression de la table pourra être faite en ajoutant un script sql « delete.sql » à ceux du répertoire sql et une cible « delete » au fichier build.xml.
Le fichier « delete.sql » contient le script :
DROP TABLE Fortune if exists;
La cible à ajouter au fichier build.xml prend alors la forme suivante :
<target name="db­delete">
<java classname="org.hsqldb.util.ScriptTool" fork="yes">
<arg value="­url"/>
<arg value="jdbc:hsqldb:hsql:"/>
<arg value="­database"/>
<arg value="//localhost:1701"/>
<arg value="­script"/>
<arg value="sql/delete.sql"/>
<classpath refid="hsql.classpath"/>
</java>
</target>
­ 19/21 ­
M1 – STL ­ Composants
UPMC
­ 20/21 ­
Février­Juin 2007
M1 – STL ­ Composants
UPMC
Février­Juin 2007
TME
L'objet du TME est d'implémenter l'application HelloFortune en suivant la démarche décrite dans la partie TD du document. Cette application n'utilisera pas la génération automatique de clé pour la base de données, elle suivra donc exactement l'exemple donné. En particulier il faudra mettre en oeuvre les scripts de création et remplissage de la base de donnée.
­ 21/21 ­