Added: french translation, revdiff and typos

git-svn-id: https://svn.jboss.org/repos/hibernate/trunk/Hibernate3/doc@8719 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
Anthony Patricio 2005-11-30 15:54:05 +00:00
parent f3ad07df1b
commit bc3ea52fb6
4 changed files with 632 additions and 344 deletions

View File

@ -68,7 +68,7 @@
de données. Une factory (fabrique) de <literal>Session</literal> et un client
de <literal>ConnectionProvider</literal>. Peut contenir un cache optionnel de
données (de second niveau) qui est réutilisable entre les différentes transactions
que cela soit au sein du même processus (JVLM) ou par plusieurs noeuds d'un cluster.
que cela soit au sein du même processus (JVLM) ou par plusieurs n½uds d'un cluster.
</para>
</listitem>
</varlistentry>
@ -93,7 +93,7 @@
et la fonction métier. Ceux-ci sont en général les objets de type JavaBean
(ou POJOs) ; la seule particularité est qu'ils sont associés avec une (et
une seule) <literal>Session</literal>. Dès que la <literal>Session</literal>
est fermée, ils seront détachés et libre d'être utilisés par n'importe laquelle
est fermée, ils seront détachés et libres d'être utilisés par n'importe laquelle
des couches de l'application (ie. de et vers la présentation en tant que Data
Transfer Objects - DTO : objet de transfert de données).
</para>
@ -118,7 +118,7 @@
pour définir une unité de travail atomique. Abstrait l'application des
transactions sous-jacentes qu'elles soient JDBC, JTA ou CORBA. Une
<literal>Session</literal> peut fournir plusieurs <literal>Transaction</literal>s
dans certain cas. Toutefois, la délimitation des transactions, via l'API d'Hibernate
dans certains cas. Toutefois, la délimitation des transactions, via l'API d'Hibernate
ou par la <literal>Transaction</literal> sous-jacente, n'est jamais optionnelle!
</para>
</listitem>
@ -147,7 +147,7 @@
<listitem>
<para>
Hibernate fournit de nombreuses interfaces d'extensions optionnelles que
vous pouvez implémenter pour personnaliser le comportement de votre couche de persistence.
vous pouvez implémenter pour personnaliser le comportement de votre couche de persistance.
Reportez vous à la documentation de l'API pour plus de détails.
</para>
</listitem>
@ -166,8 +166,8 @@
<sect1 id="architecture-states" revision="1">
<title>Etats des instances</title>
<para>
Une instance d'une classe persistante être dans l'un des trois états suivants,
définit par rapport à un <emphasis>contexte de persistance</emphasis>.
Une instance d'une classe persistante peut être dans l'un des trois états suivants,
définis par rapport à un <emphasis>contexte de persistance</emphasis>.
L'objet <literal>Session</literal> d'hibernate correspond à ce concept de
contexte de persistance :
</para>
@ -274,36 +274,36 @@
<title>Sessions Contextuelles</title>
<para>
Certaines applications utilisant Hibernate ont besoin d'une sorte de session "contextuelle", où
une session est liée au scope d'un context particulier. Cependant, les applications ne définissent
pas toutes la notion de context de la même manière, et différents contexts définissent différents
scopes à la notion de "courant". Les applications à base d'Hibernate, versions précédentes à la 3.0
une session est liée à la portée d'un contexte particulier. Cependant, les applications ne définissent
pas toutes la notion de contexte de la même manière, et différents contextes définissent différentes
portées à la notion de "courant". Les applications à base d'Hibernate, versions précédentes à la 3.0
utilisaient généralement un principe maison de sessions contextuelles basées sur le <literal>ThreadLocal</literal>,
ainsi que sur des classes helper comme <literal>HibernateUtil</literal>, ou utilisaient des
ainsi que sur des classes utilitaires comme <literal>HibernateUtil</literal>, ou utilisaient des
framework tiers (comme Spring ou Pico) qui fournissaient des sessions contextuelles basées sur
proxy/interception-based.
l'utilisation de proxy/interception.
</para>
<para>
A partir de la version 3.0.1, Hibernate a ajouté la méthode <literal>SessionFactory.getCurrentSession()</literal>.
Initiallement, cela demandait l'usage de transactions <literal>JTA</literal>, où la
transaction <literal>JTA</literal> définissait et le scope et le context de la session courante.
Initialement, cela demandait l'usage de transactions <literal>JTA</literal>, où la
transaction <literal>JTA</literal> définissait la portée et le contexte de la session courante.
L'équipe Hibernate pense que, étant donnée la maturité des implémentations de <literal>JTA TransactionManager</literal> ,
la plupart (sinon toutes) des applications devraient utiliser la gestion des transactions par <literal>JTA</literal>
qu'elles soient ou non déployées dans un conteneur <literal>J2EE</literal> container. Par conséquent,
vous devriez toujours conextualiser vos sessions, si vous en avez besoin, via la méthode basée sur JTA.
qu'elles soient ou non déployées dans un conteneur <literal>J2EE</literal>. Par conséquent,
vous devriez toujours contextualiser vos sessions, si vous en avez besoin, via la méthode basée sur JTA.
</para>
<para>
Cependant, depuis la version 3.1, la logique derrière
<literal>SessionFactory.getCurrentSession()</literal> est désormais pluggable.
<literal>SessionFactory.getCurrentSession()</literal> est désormais branchable.
A cette fin, une nouvelle interface d'extension (<literal>org.hibernate.context.CurrentSessionContext</literal>)
et un nouveau paramètre de configuration (<literal>hibernate.current_session_context_class</literal>)
ont été ajoutés pour permettre de configurer d'autres moyens de définir le scope et le context des
ont été ajoutés pour permettre de configurer d'autres moyens de définir la portée et le contexte des
sessions courantes.
</para>
<para>
Allez voir les Javadocs de l'interface <literal>org.hibernate.context.CurrentSessionContext</literal>
pour une discussion détaillée de son contrat. Elle définit une seule méthode,
pour une description détaillée de son contrat. Elle définit une seule méthode,
<literal>currentSession()</literal>, depuis laquelle l'implémentation est responsable
de traquer la session courante du context. Hibernate fournit deux implémentation
de traquer la session courante du contexte. Hibernate fournit deux implémentation
de cette interface.
</para>
@ -331,17 +331,17 @@
nous vous conseillons d'utiliser l'API Hibernate <literal>Transaction</literal> pour masquer le système
de transaction utilisé. Si vous exécutez sous un conteneur EJB qui supporte CMT, vous n'avez besoin d'aucune
opérations de démarcations de session ou transaction dans votre code puisque tout
est géré de manière déclarative. Réferrez vous à <xref linkend="transactions"/> pour plus d'informations
est géré de manière déclarative. Référez vous à <xref linkend="transactions"/> pour plus d'informations
et des exemples de code.
</para>
<para>
Le paramètre de configuration <literal>hibernate.current_session_context_class</literal>
définit qu'elle implémentation de <literal>org.hibernate.context.CurrentSessionContext</literal>
doit être utilisé. Notez que pour assurer la compatibilité avec les versions précédentes, si
définit quelle implémentation de <literal>org.hibernate.context.CurrentSessionContext</literal>
doit être utilisée. Notez que pour assurer la compatibilité avec les versions précédentes, si
ce paramètre n'est pas défini mais qu'un <literal>org.hibernate.transaction.TransactionManagerLookup</literal>
est configuré, Hibernate utilisera le <literal>org.hibernate.context.JTASessionContext</literal>.
La valeur de ce paramètre devrait juste nomer la classe d'implémentation a utiliser,
La valeur de ce paramètre devrait juste nommer la classe d'implémentation à utiliser,
pour les deux implémentations fournies, il y a cependant deux alias correspondant: "jta" et "thread".
</para>

File diff suppressed because it is too large Load Diff

View File

@ -6,15 +6,15 @@
Les classes persistantes sont les classes d'une application qui implémentent
les entités d'un problème métier (ex. Client et Commande dans une application
de commerce électronique).
Toutes les instances d'une classe persistante ne sont pas considérées être
dans l'état persistant - une instance peut au lieu de ça être éphémères ou détachées.
Toutes les instances d'une classe persistante ne sont pas forcément
dans l'état persistant - au lieu de cela, une instance peut être éphémère (NdT : transient) ou détachée.
</para>
<para>
Hibernate fonctionne de manière optimale lorsque ces classes suivent quelques règles
simples, aussi connues comme le modèle de programmation Plain Old Java Object
(POJO). Cependant, aucune de ces règles ne sont des besoins absolus. En effet, Hibernate3 suppose très peu de chose à propos
de la nature de vos objets persistants. Vous pouvez exprimez un modèle de domaine par d'autres moyens : utiliser des arbres
(POJO). Cependant, aucune de ces règles ne sont des besoins absolus. En effet, Hibernate3 suppose très peu de choses à propos
de la nature de vos objets persistants. Vous pouvez exprimer un modèle de domaine par d'autres moyens : utiliser des arbres
d'instances de <literal>Map</literal>, par exemple.
</para>
@ -115,7 +115,7 @@ public class Cat {
<para>
<literal>Cat</literal> a un constructeur sans argument. Toutes les classes persistantes doivent avoir un
constructeur par défaut (lequel peut ne pas être publique) pour qu'Hibernate puissent les instancier en utilisant
constructeur par défaut (lequel peut ne pas être public) pour qu'Hibernate puissent les instancier en utilisant
<literal>Constructor.newInstance()</literal>. Nous recommandons fortement d'avoir un constructeur par défaut avec
au moins une visibilité <emphasis>paquet</emphasis> pour la génération du proxy à l'exécution dans Hibernate.
</para>
@ -136,8 +136,8 @@ public class Cat {
</para>
<para>
La propriété d'identifiant est strictment optionnelle. Vous pouver l'oublier et laisser Hibernate
s'occuper des identifiants de l'objet en interne. Cependant, nous ne recommandons pas cela.
La propriété d'identifiant est strictement optionnelle. Vous pouver l'oublier et laisser Hibernate
s'occuper des identifiants de l'objet en interne. Toutefois, nous ne le recommandons pas.
</para>
<para>
@ -174,17 +174,17 @@ public class Cat {
<sect2 id="persistent-classes-pojo-final">
<title>Favoriser les classes non finales (optionnel)</title>
<para>
Une fonctionalité clef d'Hibernate, les <emphasis>proxies</emphasis>, nécessitent
Une fonctionnalité clef d'Hibernate, les <emphasis>proxies</emphasis>, nécessitent
que la classe persistente soit non finale ou qu'elle soit l'implémentation d'une
interface qui déclare toutes les méthodes publiques.
</para>
<para>
Vous pouvez persister, grâce à Hibernate, les classes <literal>final</literal>
qui n'implémentent pas d'interface, mais vous ne pourrez pas utiliser les proxies pour les chargements d'associations retardées
qui n'implémentent pas d'interface, mais vous ne pourrez pas utiliser les proxies pour les chargements d'associations paresseuses
- ce qui limitera vos possibilités d'ajustement des performances.
</para>
<para>
Vous devriez aussi éviter de déclarer des méthodes <literal>public final</literal>sur des classes
Vous devriez aussi éviter de déclarer des méthodes <literal>public final</literal> sur des classes
non-finales. Si vous voulez utiliser une classe avec une méthode <literal>public final</literal>, vous devez
explicitement désactiver les proxies en paramétrant
<literal>lazy="false"</literal>.
@ -192,10 +192,10 @@ public class Cat {
</sect2>
<sect2 id="persistent-classes-pojo-accessors" revision="2">
<title>Déclarer les accesseurs et modifieurs des attributs persistants (optionnel)</title>
<title>Déclarer les accesseurs et mutateurs des attributs persistants (optionnel)</title>
<para>
<literal>Cat</literal> déclare des modifieurs pour toutes ses champs persistants. Beaucoup d'autres
<literal>Cat</literal> déclare des mutateurs pour toutes ses champs persistants. Beaucoup d'autres
solutions de mapping Objet/relationnel persistent directement les variables d'instance. Nous pensons
qu'il est bien mieux de fournir une indirection entre le schéma relationnel et les structures de données internes de la classe.
Par défaut, Hibernate persiste les propriétés suivant le style JavaBean, et reconnaît les noms de méthodes de la forme <literal>
@ -259,7 +259,7 @@ public class DomesticCat extends Cat {
</itemizedlist>
<para>
Hibernate garantit l'équivalance de l'identité persistante (ligne de base de données) et l'identité Java seulement
Hibernate garantit l'équivalence de l'identité persistante (ligne de base de données) et l'identité Java seulement
à l'intérieur de la portée d'une session particulière. Donc dès que nous mélangeons des instances venant de différentes
sessions, nous devons implémenter <literal>equals()</literal> et
<literal>hashCode()</literal> si nous souhaitons avoir une sémantique correcte pour les <literal>Set</literal>s.
@ -267,10 +267,10 @@ public class DomesticCat extends Cat {
<para>
La manière la plus évidente est d'implémenter <literal>equals()</literal>/<literal>hashCode()</literal>
en comparant la valeur de l'identifiant des deux objets.Si cette valeur est identique, les deux
en comparant la valeur de l'identifiant des deux objets. Si cette valeur est identique, les deux
doivent représenter la même ligne de base de données, ils sont donc égaux (si les deux sont
ajoutés à un <literal>Set</literal>, nous n'auront qu'un seul élément dans le
<literal>Set</literal>).Malheureusement, nous ne pouvons pas utiliser cette approche avec
ajoutés à un <literal>Set</literal>, nous n'aurons qu'un seul élément dans le
<literal>Set</literal>). Malheureusement, nous ne pouvons pas utiliser cette approche avec
des identifiants générés ! Hibernate n'assignera de
valeur d'identifiant qu'aux objets qui sont persistants, une instance nouvellement créée n'aura
donc pas de valeur d'identifiant ! De plus, si une instance est non sauvegardée et actuellement dans un <literal>Set</literal>,
@ -485,7 +485,7 @@ dynamicSession.close()
soit utilisée dans le mode d'entité dynamic-map ; ou peut-être avez-vous besoin de définir une
statégie de génération de proxy différente de celle utilisée par défaut. Les deux devraient être
effectuées en définissant une implémentation de tuplizer utilisateur. Les définitions de tuplizers
sont attachées au mapping de l'entité ou du composant qu'ils sont sensés gérer. Retour à l'exemple de
sont attachées au mapping de l'entité ou du composant qu'ils sont censés gérer. Retour à l'exemple de
notre entité utilisateur :
</para>

View File

@ -15,7 +15,7 @@
<para>
Ce didacticiel est destiné aux nouveaux utilisateurs d'Hibernate mais requiert
des connaissances Java et SQL. Il est basé sur un didacticiel de Michael Gloegl,
les bibliothèques tierses que nous nommons sont pour les JDK 1.4 et 5.0. Vous
les bibliothèques tierces que nous nommons sont pour les JDK 1.4 et 5.0. Vous
pourriez avoir besoin d'autres bibliothèques pour le JDK 1.3.
</para>
@ -37,7 +37,7 @@
<para>
Supposons que nous ayons besoin d'une petite application de base de données qui
puisse stocker des événements que nous voulons suivre, et des inforomations à propos
puisse stocker des événements que nous voulons suivre, et des informations à propos
des hôtes de ces événements.
</para>
@ -68,7 +68,7 @@
Ceci est l'ensemble minimum de bibliothèques requises (notez que nous avons aussi
copié hibernate3.jar, l'archive principale) pour Hibernate. Lisez le fichier
<literal>README.txt</literal> dans le répertoire <literal>lib/</literal> de la
distribution Hibernate pour plus d'informations à propos des biliothèques tierses
distribution Hibernate pour plus d'informations à propos des biliothèques tierces
requises et optionnelles. (En fait, log4j n'est pas requis mais préféré par beaucoup
de développeurs.)
</para>
@ -162,7 +162,7 @@ public class Event {
<programlisting><![CDATA[.
+lib
<Hibernate et bibliothèques tierses>
<Hibernate et bibliothèques tierces>
+src
+events
Event.java]]></programlisting>
@ -200,7 +200,7 @@ public class Event {
<para>
Notez que la DTD Hibernate est très sophistiquée. Vous pouvez l'utiliser
pour l'auto-complétement des éléments et des attributs de mapping XML dans
votre éditeur ou votre IDE. You devriez aussi ouvrir le fichier DTD dans
votre éditeur ou votre IDE. Vous devriez aussi ouvrir le fichier DTD dans
votre éditeur de texte - c'est le moyen le plus facile d'obtenir une vue
d'ensemble de tous les éléments et attributs, et de voir les valeurs par
défaut, ainsi que quelques commentaires. Notez qu'Hibernate ne chargera
@ -328,7 +328,7 @@ public class Event {
<programlisting><![CDATA[.
+lib
<Hibernate et bibliothèques tierses>
<Hibernate et bibliothèques tierces>
+src
Event.java
Event.hbm.xml]]></programlisting>
@ -343,7 +343,7 @@ public class Event {
<title>Configuration d'Hibernate</title>
<para>
Nous avons maintenant une classe persistante et son fichier de mapping. Il les temps de
Nous avons maintenant une classe persistante et son fichier de mapping. Il est temps de
configurer Hibernate. Avant ça, nous avons besoin d'une base de données. HSQL DB, un
SGBD SQL basé sur Java et travaillant en mémoire, peut être téléchargé à partir du site
web de HSQL. En fait, vous avez seulement besoin de <literal>hsqldb.jar</literal>. Placez
@ -354,7 +354,7 @@ public class Event {
Créez un répertoire appelé <literal>data</literal> à la racine du répertoire de développement -
c'est là que HSQL DB stockera ses fichiers de données. Démarrez maintenant votre base de données
en exécutant <literal>java -classpath lib/hsqldb.jar org.hsqldb.Server</literal> dans votre répertoire de travail.
Vous observez qu'elle démarre et ouvre un socket TCP/IP, c'est là que notre application
Vous observez qu'elle démarre et ouvre une socket TCP/IP, c'est là que notre application
se connectera plus tard. Si vous souhaitez démarrez à partir d'une nouvelle base de données
pour ce tutoriel (faites <literal>CTRL + C</literal> dans la fenêtre the window), effacez
le répertoire <literal>data/</literal> et redémarrez HSQL DB à nouveau.
@ -453,7 +453,7 @@ public class Event {
d'installé - récupérez-le à partir de <ulink url="http://ant.apache.org/bindownload.cgi"> la page
de téléchargement de Ant</ulink>. Comment installer Ant ne sera pas couvert ici. Référez-vous
au <ulink url="http://ant.apache.org/manual/index.html">manuel d'Ant</ulink>. Après que
vous aurez installé Ant, nous pouvons commencer à créer le fichier de construction. Il
vous aurez installé Ant, nous pourrons commencer à créer le fichier de construction. Il
s'appellera <literal>build.xml</literal> et sera placé directement dans le répertoire de
développement.
</para>
@ -523,7 +523,7 @@ Total time: 1 second ]]></programlisting>
<para>
Il est temps de charger et de stocker quelques objets <literal>Event</literal>,
mais d'abord nous devons compléter la configuration avec du code
d'infrastructure. Nous devons démarrer Hibernate. Ce démarrage inclus la construction
d'infrastructure. Nous devons démarrer Hibernate. Ce démarrage inclut la construction
d'un objet <literal>SessionFactory</literal> global et le stocker quelque part
facile d'accès dans le code de l'application. Une <literal>SessionFactory</literal>
peut ouvrir des nouvelles <literal>Session</literal>s. Une <literal>Session</literal>
@ -862,7 +862,7 @@ public class Person {
<para>
Nous allons maintenant créer une association entre ces deux entités. Évidemment,
des personnes peuvent participer aux événements, et des événements ont des participants.
Les question de conception que nous devons traiter sont : directivité, pluralité et comportement
Les questions de conception que nous devons traiter sont : direction, cardinalité et comportement
de la collection.
</para>
@ -991,8 +991,8 @@ public class Person {
Hibernate surveille les changements et exécute le SQL correspondant. Le processus de
synchronisation de l'état de la mémoire avec la base de données, généralement seulement à la fin
d'une unité de travail, est appelé <emphasis>flushing</emphasis>. Dans notre code, l'unité de travail
s'achève par un commit (ou rollback) de la transaction avec la base de données - comme définit
par notre option <literal>thread</literal> de configuration pour la calsse <literal>CurrentSessionContext</literal>.
s'achève par un commit (ou rollback) de la transaction avec la base de données - comme défini
par notre option <literal>thread</literal> de configuration pour la classe <literal>CurrentSessionContext</literal>.
</para>
<para>
@ -1032,7 +1032,7 @@ public class Person {
<para>
L'appel à <literal>update</literal> rend un objet détaché à nouveau persistant, vous pourriez
dire qu'il le lie à une unité de travail, ainsi toutes les modifications (ajout.suppression) que vous avez faites
dire qu'il le lie à une unité de travail, ainsi toutes les modifications (ajout, suppression) que vous avez faites
pendant qu'il était détaché peuvent être sauvegardées dans la base de données
(il se peut que vous ayez besoin de modifier quelques unes des méthodes précédentes
pour retourner cet identifiant).
@ -1078,7 +1078,7 @@ public class Person {
<title>Collection de valeurs</title>
<para>
Nous ajoutons une collection de d'objets de type de valeur à l'entité <literal>Person</literal>.
Nous ajoutons une collection d'objets de type de valeur à l'entité <literal>Person</literal>.
Nous voulons stocker des adresses email, donc le type que nous utilisons est <literal>String</literal>,
et la collection est encore un <literal>Set</literal> :
</para>
@ -1107,7 +1107,7 @@ public void setEmailAddresses(Set emailAddresses) {
mais une collection d'éléments de type <literal>String</literal> (le nom en minuscule vous
indique que c'est un type/convertisseur du mapping Hibernate). Une fois encore, l'attribut
<literal>table</literal> de l'élément <literal>set</literal> détermine le nom de la table pour la
collection. L'élément <literal>key</literal> définit la nom de la colonne de la clef étrangère
collection. L'élément <literal>key</literal> définit le nom de la colonne de la clef étrangère
dans la table de la collection. L'attribut <literal>column</literal> dans l'élément
<literal>element</literal> définit le nom de la colonne où les valeurs de <literal>String</literal>
seront réellement stockées.
@ -1158,7 +1158,7 @@ public void setEmailAddresses(Set emailAddresses) {
}]]></programlisting>
<para>
Cette fois ci, nous n'avons pas utilisé une requête de chargement aggressif (<emphasis>fetch</emphasis>)
Cette fois ci, nous n'avons pas utilisé une requête de chargement agressif (<emphasis>fetch</emphasis>)
pour initialiser la collection. Par conséquent, l'invocation du getter déclenchera un
select supplémentaire pour l'initialiser. Traquez les logs SQL et tentez d'optimiser
ce cas avec un chargement aggressif.
@ -1171,7 +1171,7 @@ public void setEmailAddresses(Set emailAddresses) {
<para>
Ensuite nous allons mapper une association bidirectionnelle - faire fonctionner
l'association entre une personne et et un événement à partir des deux côtés en Java.
l'association entre une personne et un événement à partir des deux côtés en Java.
Bien sûr, le schéma de la base de données ne change pas, nous avons toujours une pluralité
many-to-many. Une base de données relationnelle est plus flexible qu'un langage de
programmation réseau, donc elle n'a pas besoin de direction de navigation - les données
@ -1212,7 +1212,7 @@ public void setParticipants(Set participants) {
<para>
Ce que signifie qu'Hibernate devrait prendre l'autre côté - la classe <literal>Person</literal> -
s'il a besoin de renseigner des informations à propos du lien entre les deux. Ce sera
beaucoup plus facile à comprendre une fois que vous verrez comment la lien bidirectionnel
beaucoup plus facile à comprendre une fois que vous verrez comment le lien bidirectionnel
entre les deux entités est créé.
</para>
@ -1222,8 +1222,8 @@ public void setParticipants(Set participants) {
<title>Travailler avec des liens bidirectionnels</title>
<para>
Premièrement, gardez à l'esprit qu'Hibernate n'affecte pas la sémantique normal de Java.
Comment avons-nous créer un lien entre une <literal>Person</literal> et un <literal>Event</literal>
Premièrement, gardez à l'esprit qu'Hibernate n'affecte pas la sémantique normale de Java.
Comment avons-nous créé un lien entre une <literal>Person</literal> et un <literal>Event</literal>
dans l'exemple unidirectionnel ? Nous avons ajouté une instance de <literal>Event</literal>
à la collection des références d'événement d'une instance de <literal>Person</literal>. Donc,
évidemment, si vous voulons rendre ce lien bidirectionnel, nous devons faire la même chose de
@ -1285,12 +1285,277 @@ public void removeFromEvent(Event event) {
-->
</sect2>
</sect1>
<sect1 id="tutorial-webapp">
<title>Part 3 - L'application web EventManager</title>
<sect1 id="tutorial-summary">
<para>
Une application web Hibernate utilise la <literal>Session</literal> et <literal>Transaction</literal>
comme une application standalone. Cependant, quelques patterns sont utiles. Nous allons coder une
<literal>EventManagerServlet</literal>. Cette servlet peut lister tous les évènements stockés dans
la base de données, et fournir une formulaire HTML pour saisir d'autres évènements.
</para>
<sect2 id="tutorial-webapp-servlet">
<title>Ecrire la servlet de base</title>
<para>
Créons une nouvelle classe dans notre répertoire source, dans le package <literal>events</literal>:
</para>
<programlisting><![CDATA[package events;
// Imports
public class EventManagerServlet extends HttpServlet {
private final SimpleDateFormat dateFormatter =
new SimpleDateFormat("dd.MM.yyyy");
// Servlet code
}]]></programlisting>
<para>
Le <literal>dateFormatter</literal> est un outil que nous utiliserons plus tard pour convertir les objets
<literal>Date</literal> depuis et vers des chaines de caractères. Il est propice de n'avoir qu'un
formatter comme membre de la servlet.
</para>
<para>
La servlet n'accepte que les requêtes HTTP <literal>GET</literal>, la méthode à implémenter est donc
<literal>doGet()</literal>:
</para>
<programlisting><![CDATA[protected void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
try {
// Begin unit of work
HibernateUtil.getSessionFactory()
.getCurrentSession().beginTransaction();
// Process request and render page...
// End unit of work
HibernateUtil.getSessionFactory()
.getCurrentSession().getTransaction().commit();
} catch (Exception ex) {
HibernateUtil.getSessionFactory()
.getCurrentSession().getTransaction().rollback();
throw new ServletException(ex);
}
}]]></programlisting>
<para>
La pattern que nous utilisons ici est appelé <emphasis>session-per-request</emphasis>.
Lorsqu'une requête touche la servlet, une nouvelle <literal>Session</literal> hibernate est
ouverte à l'invocationde <literal>getCurrentSession()</literal> sur la
<literal>SessionFactory</literal>. Ensuite, une transaction avec la base de données est démarrée&mdash;
tous les accès à la base de données interviennent au sein de la transactiton, peu importe que les données
soient lues ou écrites (nous n'utilisons pas le mode auto-commit dans les applications).
</para>
<para>
Ensuite, les actions possibles de la requêtes sont exécutées et la réponse HTML
est rendue. Nous en parlerons plus tard.
</para>
<para>
Enfin, l'unité de travail s'achève lorsque l'exécution et le rendu sont achevés.
Si un problème survient lors de ces deux phases, une exception est soulevée et la
transaction avec la base de données subit un rollback. Voila pour le pattern
<literal>session-per-request</literal>. Au lieu d'un code de démarcation de transaction
au sein de chaque servlet, vous pouvez écrire un filtre de servlet.
Voir le site Hibernate et le Wiki pour plus d'information sur ce pattern, appelé
<emphasis>Open Session in View</emphasis>&mdash; vous en aurez besoin dès que vous
utiliserez des JSPs et non plus des servlets pour le rendu de vos vues.
</para>
</sect2>
<sect2 id="tutorial-webapp-processing">
<title>Procéder et rendre</title>
<para>
Implémentons l'exécution de la requête et le rendu de la page.
</para>
<programlisting><![CDATA[// Write HTML header
PrintWriter out = response.getWriter();
out.println("<html><head><title>Event Manager</title></head><body>");
// Handle actions
if ( "store".equals(request.getParameter("action")) ) {
String eventTitle = request.getParameter("eventTitle");
String eventDate = request.getParameter("eventDate");
if ( "".equals(eventTitle) || "".equals(eventDate) ) {
out.println("<b><i>Please enter event title and date.</i></b>");
} else {
createAndStoreEvent(eventTitle, dateFormatter.parse(eventDate));
out.println("<b><i>Added event.</i></b>");
}
}
// Print page
printEventForm(out);
listEvents(out);
// Write HTML footer
out.println("</body></html>");
out.flush();
out.close();]]></programlisting>
<para>
Ce style de code avec un mix de Java et d'HTML ne serait pas scalable
dans une application plus complexe&mdash;gardez à l'esprit que nous ne faisons qu'illustrer
les concepts basiques d'Hibernate dans ce tutoriel. Ce code affiche une en tête et un pied de page
HTML. Dans cette page, sont affichés un formulaire pour la saisie d'évènements ainsi
qu'une liste de tous les évènements de la base de données. La première méthode
est triviale est ne fait que sortir de l'HTML:
</para>
<programlisting><![CDATA[private void printEventForm(PrintWriter out) {
out.println("<h2>Add new event:</h2>");
out.println("<form>");
out.println("Title: <input name='eventTitle' length='50'/><br/>");
out.println("Date (e.g. 24.12.2009): <input name='eventDate' length='10'/><br/>");
out.println("<input type='submit' name='action' value='store'/>");
out.println("</form>");
}]]></programlisting>
<para>
La méthode <literal>listEvents()</literal> utilise la
<literal>Session</literal> Hibernate liée au thread courant pour exécuter la
requête:
</para>
<programlisting><![CDATA[private void listEvents(PrintWriter out) {
List result = HibernateUtil.getSessionFactory()
.getCurrentSession().createCriteria(Event.class).list();
if (result.size() > 0) {
out.println("<h2>Events in database:</h2>");
out.println("<table border='1'>");
out.println("<tr>");
out.println("<th>Event title</th>");
out.println("<th>Event date</th>");
out.println("</tr>");
for (Iterator it = result.iterator(); it.hasNext();) {
Event event = (Event) it.next();
out.println("<tr>");
out.println("<td>" + event.getTitle() + "</td>");
out.println("<td>" + dateFormatter.format(event.getDate()) + "</td>");
out.println("</tr>");
}
out.println("</table>");
}
}]]></programlisting>
<para>
FEnfin, l'action <literal>store</literal> renvoie à la méthode
<literal>createAndStoreEvent()</literal>, qui utilise aussi la
<literal>Session</literal> du thread courant:
</para>
<programlisting><![CDATA[protected void createAndStoreEvent(String title, Date theDate) {
Event theEvent = new Event();
theEvent.setTitle(title);
theEvent.setDate(theDate);
HibernateUtil.getSessionFactory()
.getCurrentSession().save(theEvent);
}]]></programlisting>
<para>
La servlet est faite. Une requête à la servlet sera exécutée par une seule
<literal>Session</literal> et <literal>Transaction</literal>. Comme pour une application
standalone, Hibernate peut automatiquement lier ces objets au thread courant d'exécution.
Cela vous laisse la liberté de séparer votre code en couches et d'accéder à la
<literal>SessionFactory</literal> par le moyen que vous voulez.
Généralement, vous utiliserez des conceptions plus sophistiquées et déplacerez
le code d'accès aux données dans une couche DAO. Voir le wiki Hibernate pour plus
d'exemples.
</para>
</sect2>
<sect2 id="tutorial-webapp-deploy">
<title>Déployer et tester</title>
<para>
Pour déployer cette application, vous devez créer une archive Web, un War. Ajoutez
la cible Ant suivante dans votre <literal>build.xml</literal>:
</para>
<programlisting><![CDATA[<target name="war" depends="compile">
<war destfile="hibernate-tutorial.war" webxml="web.xml">
<lib dir="${librarydir}">
<exclude name="jsdk*.jar"/>
</lib>
<classes dir="${targetdir}"/>
</war>
</target>]]></programlisting>
<para>
Cette cible créé un fichier nommé <literal>hibernate-tutorial.war</literal>
dans le répertoire de votre projet. Elle package les bibliothèques et le descripteur <literal>web.xml</literal>
qui est attendu dans le répertoire racine de votre projet:
</para>
<programlisting><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<servlet>
<servlet-name>Event Manager</servlet-name>
<servlet-class>events.EventManagerServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Event Manager</servlet-name>
<url-pattern>/eventmanager</url-pattern>
</servlet-mapping>
</web-app>]]></programlisting>
<para>
Avant de compiler et déployer l'application web, notez qu'une bibliothèque supplémentaire
est requise: <literal>jsdk.jar</literal>. C'est le kit de développement de Servlet Java,
si vous ne disposez pas de cette bibliothèque, prenez la sur le site de Sun et copiez la
dans votre répertoire des bibliothèques. Cependant, elle ne sera utilisée uniquement pour la
compilation et sera exclue du paackage WAR.
</para>
<para>
Pour construire et déployer, appelez <literal>ant war</literal> dans votre projet et
copier le fichier <literal>hibernate-tutorial.war</literal> dans le répertoire <literal>webapp</literal> de tomcat
Si vous n'avez pas installé Tomcat, téléchargez le et suivez la notice d'installation.
Vous n'avez pas à modifier la configuration Tomcat pour déployer cette application.
</para>
<para>
Une fois l'application déployée et Tomcat lancé, accédez à l'application via
<literal>http://localhost:8080/hibernate-tutorial/eventmanager</literal>.
Assurez vous de consulter les traces tomcat pour observer l'initialisation
d'Hibernate à la première requête touchant votre servlet (l'initialisation statique dans <literal>HibernateUtil</literal>
est invoquée) et pour vérifier qu'aucune exception ne survienne.
</para>
</sect2>
</sect1>
<sect1 id="tutorial-summary" revision="1">
<title>Résumé</title>
<para>
Ce didacticiel a couvert les bases de l'écriture d'une simple application Hibernate autonome.
Ce didacticiel a couvert les bases de l'écriture d'une simple application Hibernate ainsi qu'une petite application web.
</para>
<para>