Persistance des objets
Dans cette partie, nous illustrons la persistance à travers l'application room-manager que vous allez devoir compléter.
La première partie de cette séance présente l'application et les différents concepts à apprendre pour la comprendre. La seconde partie présente la persistance (que vous avez déjà vu dans d'autres matières) en Java EE.
Présentation du projet Room-Manager¶
- v1.5 : version ligne de commande.
- Une version de base vous est fournie ; vous devrez la compléter.
Objectifs pédagogique¶
- Manipuler les concepts logiciels modernes :
injection de dépendancesavecGoogle Guice- persistance JavaEE
JPAavecHibernate
- Utiliser l'outillage JavaEE (
Maven,CheckSyle,PMD,JUnit,Cobertura, etc...) - Utiliser des bibliothèques tierces open-source (
slf4j, etc...)
Démarrer l'application avec le livrable¶
Le binaire de l'application est également livrée sous forme d'archive .zip: room-manager-1.5-bin.zip`. Pour l'installer, il suffit de décompresser l'archive (voir le contenu ci-après).
Sous Windows : double-clic sur l'icône du fichier .jar (si installation de Java par l'installeur).
En ligne de commande (bash ou Dos) :
Notez qu'il n'y a aucune indication de Class-Path ni de Main-Class dans la ligne de commande !Interface ligne de commandes :
INFO 21:35:34.870 f.i.rm.App [App.java:119] - Room-Manager version 1.0 started
INFO 21:35:35.115 f.i.rm.App [App.java:122] - starting persistency service
usage: room-manager.jar
-c <name> Create new room
-h Display help message
-l List all rooms
-q Quit
Contenu de l'archive du livrable¶
Toutes les bibliothèques dépendantes sont stockées dans le dossier lib, sous l'archive JAR.
<room-manager directory>
|
- room-manager.jar
|
- lib
- antlr-2.7.6.jar
- aopalliance-1.0.jar
- asm-3.1.jar
- cglib-2.2.jar
- commons-cli-1.2.jar
- commons-collections-3.1.jar
- dom4j-1.6.1.jar
- guice-3.0.jar
- guice-persist-3.0.jar
- h2-1.3.160.jar
- hibernate-commons-annotations-3.2.0.Final.jar
- hibernate-core-3.6.0.Final.jar
- hibernate-entitymanager-3.6.0.Final.jar
- hibernate-jpa-2.0-api-1.0.0.Final.jar
- javassist-3.12.0.GA.jar
- javax.inject-1.jar
- jta-1.1.jar
- logback-classic-1.0.13.jar
- logback-core-1.0.13.jar
- slf4j-api-1.6.1.jar
Voici le contenu du fichier MANIFEST.MF qui informe la JVM des dépendances à l'exécution du programme :
Archive: /Users/fred/workspace_iut/teaching.s4_jee/03_persistence/room-manager/target/room-manager-1.0/room-manager.jar
inflating: META-INF/MANIFEST.MF
Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Created-By: Apache Maven
Built-By: fred
Build-Jdk: 1.7.0_25
Main-Class: fr.iut.rm.App
Class-Path: lib/guice-3.0.jar lib/javax.inject-1.jar lib/aopalliance-1
.0.jar lib/guice-persist-3.0.jar lib/slf4j-api-1.6.1.jar lib/logback-
classic-1.0.13.jar lib/logback-core-1.0.13.jar lib/hibernate-jpa-2.0-
api-1.0.0.Final.jar lib/hibernate-entitymanager-3.6.0.Final.jar lib/h
ibernate-core-3.6.0.Final.jar lib/antlr-2.7.6.jar lib/commons-collect
ions-3.1.jar lib/dom4j-1.6.1.jar lib/hibernate-commons-annotations-3.
2.0.Final.jar lib/jta-1.1.jar lib/cglib-2.2.jar lib/asm-3.1.jar lib/j
avassist-3.12.0.GA.jar lib/h2-1.3.160.jar lib/commons-cli-1.2.jar
Les informations de l'entrée Class-Path sont stockées par convention à 80 colonnes, chaque bibliothèque (.jar) séparée d'un caractère espace !
Construction des Livrables¶
Le projet est outillé sous Maven ; on tire ainsi profit des déclarations de dépendances du pom.xml pour automatiquement construire le livrable (nommé assembly).
Les sources sont fournies : room-manager-1.5-src.zip.
Construction du livrable : plugin Maven Assembly¶
La commande mvn assembly:assembly1 permet de fabriquer entièrement le programme a livrer.
Le résultat est un fichier .zip dans le répertoire target qui contient (cf. section précédente) :
- l'archive Java (.JAR) de notre code
- l'ensemble des bibliothèques nécessaires au fonctionnement du programme
- Injection
- Google Guice
- JPA
- Hibernate (implémentation JPA)
- Module d'interprétation de commande en ligne
- Gestionnaire de traces applicatives
- Parseur XML
Comment maven a-t-il connaissance des informations à inclure ?
Le livrable est défini dans le fichier binary.xml du dossier src/main/assembly2
<?xml version="1.0" encoding="UTF-8"?>
<assembly
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" \
xsi:schemaLocation="http://maven.apache.org/xsd/assembly-1.1.0.xsd">
<id>bin</id>
<formats>
<format>zip</format>
</formats>
<files>
<file>
<source>target/${project.artifactId}-${project.version}.jar</source>
<outputDirectory>/</outputDirectory>
<destName>${project.artifactId}.jar</destName>
</file>
</files>
<dependencySets>
<dependencySet>
<outputDirectory>/lib</outputDirectory>
<unpack>false</unpack>
<scope>runtime</scope>
<useProjectArtifact>false</useProjectArtifact>
</dependencySet>
</dependencySets>
</assembly>
Construction du site web du projet : plugin Maven Site¶
La commande mvn site3 génère le site web du projet qui contient :
- la liste des dépendances et licences logicielles associées
- différents rapports d'audit
Certains des plugins mis en œuvre sont configurés dans le dossier config du projet.
Lancement de l'application depuis les sources¶
$ mvn assembly:assembly && cp target/room-manager-1.5-bin.zip /tmp && (cd /tmp && unzip -o room-manager-1.5-bin.zip && cd room-manager-1.5 && java -jar room-manager.jar)
Exercice
Objectif : Re-construire les livrables de l'application et enregistrer une salle (15 minutes).
- récupérer le code source dans la bibliothèque
- le décompresser dans un dossier
room-managerdu dépôt utilisé pour les TDs - Commiter et pousser
- construire le livrable. L'archive du livrable est dans le dossier 'target'.
- générer le site. Il faut que la version du plugin
findBugssoit 3.0.1 (faire les modifications nécessaires dans le fichierpom.xml) - faire fonctionner l'application via le livrable
- lister les salles
- créer une salle
- lister à nouveau les salles
- quitter l'application
- relancer l'application
- lister les salles
Architecture technique¶

Le patron de conception DAO (Data Access Object) est utilisé dans ce type d'application.
A savoir une claire séparation entre les classes métiers et les fonctions d'accès à la base de données (lecture/écriture/modification/supression des données de la BD).
Le paquet persistence.domain contient les classes métiers.
Le paquet persistence.dao contient les classes
réalisant la persistance des données (objets des classes métiers), c'est à dire les accès à la base de données.
Seules les classes du paquet persistence.dao.imp dépendent de la technologique de stockage utilisée (JDBS, JPA, ...).
En cas de changement de technologie, seules
ces classes sont à réécrire.

Les fonctionalités de mise à jour de la BD sont déclarées dans des interfaces (RoomDAO en étant un exemple).
Ces interfaces définissent les accès à la base de données permettant la persistance des "objets".
L'acronyme informatique anglais CRUD (pour create, read, update, delete) (parfois appelé SCRUD avec un "S" pour search) désigne les quatre opérations de base pour la persistance des données, en particulier le stockage d'informations en base de données.
L'interface RoomDAO définit les fonctionnalités de persistance relatives aux objets de la classe Room : sauvegarde, récupération, modification. L'interface RoomDAO est incomplète (l'opération de suppression n'est pas proposée).
Composants tiers¶
Interpréteur Apache-Commons CLI¶
Apache-Commons CLI4 est une bibliothèque utilitaire pour l'interprétation des commandes saisies.
...
// build options command line options
options.addOption(
OptionBuilder
.withDescription("List all rooms")
.create(LIST));
options.addOption(
OptionBuilder
.withArgName("name")
.hasArg()
.withDescription("Create new room")
.create(CREATE));
options.addOption(
OptionBuilder
.withDescription("Display help message")
.create(HELP));
options.addOption(
OptionBuilder
.withDescription("Quit")
.create(QUIT));
...
Google Guice¶
Guice permet la mise en œuvre de l'injection de dépendances.
@Override
protected final void configure() {
logger.debug("MainModule configuration started");
bind(App.class);
bind(RoomDao.class).to(RoomDaoImpl.class);
logger.debug("MainModule configuration done");
}
Remarquez comment sont liées l'application (App) ainsi que l'implémentation de DAO.
Traces applicative¶
Un framework d'abstraction des traces applicatives est utilisé dans le programme : slf4j. Plusieurs vrais frameworks d'implémentation des traces peuvent ainsi être utilisés (intégré à Java, log4j, etc.). Changer d'implémentation devient alors transparent afin que l'application puisse facilement s'intégrer à d'autres systèmes possédant déjà une solution de traces applicatives (cas des Conteneurs Java EE).
La configuration des traces est réalisée dans le fichier logback.xml.
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%-5level %d{HH:mm:ss.SSS} %logger{10} [%file:%line] - %msg%n</pattern>
</encoder>
</appender>
<root level="${log.root.level}">
<appender-ref ref="STDOUT"/>
</root>
<logger name="fr.iut.rm" level="info"/>
<logger name="org.hibernate" level="warn"/>
<logger name="org.hibernate.SQL" level="debug"/>
<logger name="cli" level="info">
<appender-ref ref="FILE"/>
</logger>
</configuration>
Pour que les traces soit enregistrées dans le fichier ~/.log
<configuration>
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>${user.home}/.log</file>
<encoder>
<pattern>%-5level %d{HH:mm:ss.SSS} %logger{10} [%file:%line] - %msg%n</pattern>
</encoder>
</appender>
<root level="${log.root.level}">
<appender-ref ref="FILE"/>
</root>
<logger name="fr.iut.rm" level="info"/>
<logger name="org.hibernate" level="warn"/>
<logger name="org.hibernate.SQL" level="debug"/>
<logger name="cli" level="info">
<appender-ref ref="FILE"/>
</logger>
</configuration>
H2¶
H25 est une base de données SQL implémentée en Java et accessible en JDBC6 (JDBC est un standard Java de connexion aux bases de données).
H2 supporte des modes serveur (stand-alone) ou embarqué (embedded). Le stockage peut aussi bien être en mémoire (in memory) ou sur système de fichiers (filesystem).
Modèle métier¶
Composé simplement d'une classe Room qui respecte la norme Bean aussi nommé javaBean :
- un constructeur vide publique
- des
accesseurs
ainsi que des attributs (id et name).
À souligner la présence d'annotations JPA (présenté dans les sections suivantes) :
- à la déclaration de la classe
- à la déclaration des attributs de la classe
package fr.iut.rm.persistence.domain;
import javax.persistence.*;
/**
* A classic room
*/
@Entity
@Table(name = "room")
public class Room {
/**
* sequence generated id
*/
@Id
@GeneratedValue
private long id;
/**
* Room's name
*/
@Column(nullable = false, unique = true)
private String name;
/**
* Default constructor (do nothing)
*/
public Room() {
// do nothing
}
...
JPA, Java Persistance API¶
Notons qu'en français, on dit persistance et en anglais, persistence.
Il est nécessaire de rendre certains objets de l'application accessibles en permanence (même après un redémarrage, une mise à jour, un changement de machine, etc.)
Une solution est la persistance des objets dans des bases de données relationnelles :
- le stockage se fait donc sous forme de lignes stockées (appelé enregistrements) dans une ou plusieurs tables composées de différentes colonnes
- une clé primaire permet d'identifier les données (elle est stockée dans une colonne particulière)
Problème : Le monde objet\Classe est différent du monde relationnel
Les classes ne sont pas des tables (les objets ne sont pas des enregistrements) !
- il n'y a pas de notion d'héritage dans le monde relationnel ;
- les références aux collections sont inversées ;
- il n'y a pas la même notion d'égalité (primary key vs. instance)
Solution : JPA et Mapping Relationnel-Objet (ou ORM, Object Relationnal Mapping)
- Illusion de manipuler une base orientée objet dans une base relationnelle : il s'agit de créer une correpondance des classes à une base de données relationnelles.
- Différents ORM framework propriétaires le permettent (Hibernate, Ibatis, etc.). Cependant, les dernières versions de JavaEE ont publié un standard :
JPApourJava Pesistence API. Une partie des frameworks propriétaires ont implémenté le standard, dontHibernate, utilisé dans l'application Room-Manager.
Littéralement « Java Persistence API », il s’agit d’un standard faisant partie intégrante de la plate-forme Java EE, une spécification qui définit un ensemble de règles permettant la gestion de la correspondance entre des objets Java et une base de données, ou autrement formulé la gestion de la persistance. les ORM plateformes réalisent cette correspondance.
Configuration de ORM¶
L'élément de premier niveau pour faire fonctionner JPA est l'EntityManager7. Ce dernier est configuré au moyen du fichier persistence.xml qui doit être placé dans le dossier META-INF de l'archive (resources/META-INF dans les sources).
<?xml version="1.0" encoding="UTF-8" ?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0">
<!-- JPA Test Unit -->
<persistence-unit name="room-manager" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<!-- Need to add all classes due to JPA persistence file scope problem -->
<class>fr.iut.rm.persistence.domain.Room</class>
<properties>
<property name="hibernate.hbm2ddl.auto"
value="update"/>
<property name="hibernate.showSql"
value="true"/>
<!-- H2 -->
<property name="hibernate.dialect"
value="org.hibernate.dialect.H2Dialect"/>
<property name="hibernate.connection.driver_class"
value="org.h2.Driver"/>
<property name="hibernate.connection.url"
value="jdbc:h2:room-manager;DB_CLOSE_DELAY=-1"/>
</properties>
</persistence-unit>
</persistence>
Parmi les informations importantes contenues dans les balises, on peut noter :
- le nom de l'unité de persistance "base de données" (ici la base de données est stockée dans le répertoire courant sous le nom room-manager). D'autres possibilités plus fiables existent :
- la base de données est en mémoire vive (les données ne sont pas réellement persistantes) :
- la base de données est stockée dans le répertoire ~/JEE/BD/ sous le nom room-manager :
- le framework d'implémentation, org.hibernate.ejb.HibernatePersistence
- les classes Beans annotées
@Entity hibernate.hbm2ddl.auto, pour créer automatiquement le schéma- validate : valide le schéma, ne réalise aucune modification sur le schéma de la base.
- update : met à jour le schema.
- create : crée le schéma, détruisant au préalable les anciennes données.
- create-drop : supprime le schéma à la fin de la session.
Dans un programme, l'EntityManager est instancié pendant la phase de bootstrap (démarrage)
...
EntityManagerFactory emf = Persistence.createEntityManagerFactory("room-manager");
EntityManager em = emf.createEntityManager();
...
Dans le cas de l'application Room-Manager, l'instanciation est réalisée par le biais du PersistService afin que ce dernier puisse être injecté.

Utilisation de JPA¶
Décrire le Mapping entre les classes et les tables de la base¶
Afin qu'une classe Java puisse être considérée comme une entité une table, c'est à dire une classe qui est gérée par JPA, elle doit être déclarée dans le persistence.xml et annotée comme tel.
Pour Rappel :
...
@Entity
@Table(name = "room")
public class Room {
/**
* sequence generated id
*/
@Id
@GeneratedValue
private long id;
/**
* Room's name
*/
@Column(nullable = false, unique = true)
private String name;
/**
* Default constructor (do nothing)
*/
public Room() {
// do nothing
}
bean. Constructeur public sans arguments/getters/setters
- L'entité ne doit pas être finale, ses attributs non plus
- @javax.persistence.Entity permet au gestionnaire de persistance de ne pas reconnaitre la classe comme un simple POJO et de permettre de la persister
- @javax.persistence.Id indique l'identifiant unique de l'objet (cf. clé primaire)
- @javax.persistence.GeneratedValue indique que le gestionnaire de persistance se charge de générer cette valeur
- Par défaut :
- L'entité est stockée dans une table
- Chaque attribut est stocké dans une colonne
Exercice (40 minutes)
Objectif : Apprendre à utiliser JPA. Rajouter un champ description de type String, de taille maximale de 10 caractères à l'entité Room.
- Modifier la classe Room.
- Modifier temporairement le hibernate.hbm2ddl.auto pour les besoins du développement (fichier
persistence.xml) - Rajouter les annotations nécessaires (penser à la Validation vu la séance précédente).
- Vérifier que la description de la class Room générée par le plugin de Maven contient bien le champs description (fichier Room_ dans le répertoire target). SI nécessaire compile le projet via la commande en ligne de Maven
- Tester la création d'un Objet "Room" dont la description a plus de 10 caractères.
- Modifier les commandes de création et construction de liste.
Relations entre les entités¶
Les relations entre les entités peuvent avoir différentes cardinalités; ce qui doit être spécifié au travers d'annotations.
Relations entre les entités - exemple «OneToOne»¶
extrait de http://blog.paumard.org/cours/jpa/chap03-entite-relation.html
//
// Entité Commune
//
@Entity
public class Commune implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(length=40)
private String nom ;
@OneToOne
private Personne maire ;
// suite de la classe
}
En base, les choses se passent assez simplement : une colonne maire_id va être créée dans la table Commune. Cette colonne sera une clé étrangère référençant la colonne id de la table Maire. On peut imposer le nom de cette colonne en ajoutant l'annotation @JoinColumn(name="...") sur la relation maire.
//
// Entité Maire
//
@Entity
public class Personne implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(length=40)
private String nom ;
@OneToOne(mappedBy="maire") // référence la relation dans la classe Commune
private Commune commune ;
// suite de la classe
}
Exemple de relation bidirectionnelle entre les entités - «OneToMany» et «ManyToOne»¶
//
// Entité Marin
//
@Entity
public class Marin implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@ManyToOne
private Bateau monBateau ;
// reste de la classe
}
//
// Entité Bateau
//
@Entity
public class Bateau implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@OneToMany(mappedBy="monBateau")
private Collection<Marin> marins ;
// reste de la classe
}
Utilisation des objets mappés¶
Dans Room-Manager, l'utilisation des objets mappés est encadrée dans une UnitOfWork 12. Cet élément permet de gérer la connexion et les transactions avec la base de données :
- sauvegarde en base rapide (1 grosse modification plutôt que plusieurs petites)
- état de la base toujours valide (tout ou rien)
Il est possible d'interdire des opérations JPA en dehors d'un cadre transactionnel.

Cycle de vie d'une entité¶
Un objet instancié dans la JVM a plusieurs états vis-à-vis de l'EntityManager dont le rôle est d'assurer la synchronisation avec la base de données.

Gestion des transactions¶
Dans le monde des base de données relationnelles, les transactions sont essentielles à la conservation de l'intégrité du modèle de données.

Les propriétés ACID sont les quatre principaux attributs d'une transaction de données.
- Atomicité (transaction complète ou rien du tout)
- Cohérence (état nécessairement valide après transaction)
- Isolation (Pas de dépendences entre transactions)
- Durabilité (Si transaction confirmées : sur à 100% que les données sont enregistrées)
Pour autant, il n'y a pas de trace, de prime abord de la gestion des transactions dans le code source de Room-Manager. Elles sont en réalité gérées au moyen d'annotations, comme illustré dans l'extrait de code ci-après :
/**
* @param room room to persist
*/
@Override
@Transactional
public void saveOrUpdate(final Room room) {
this.em.get().persist(room);
logger.debug("Room '{}' saved", room.getName());
}
L'annotation permet d'ouvrir et commiter automatiquement la transaction. Pour autant, le vrai commit n'aura lieu qu'à la fin de l'UnitOfWork. Si une exception est levée, la transaction sera automatiquement annulée (rollback).
Patron de conception DAO¶
Le programme Room-Manager utilise le pattern (modèle de conception logicielle) de DAO pour Data Access Object 13. Son utilité est d'isoler au sein d'une seule et même couche tous les accès à la persistance (à savoir les accès (CRUD) aux données stockées de manière permanente).
Pour isoler, les accès aux données stockées, des interfaces telles que RoomDao sont créées; leur implémentation dépendra de la technique de stockage choisie (BD, fichier, ...).
package fr.iut.rm.persistence.dao;
import fr.iut.rm.persistence.domain.Room;
import java.util.List;
/**
* Data Access Object of {@link fr.iut.rm.persistence.domain.Room}
*/
public interface RoomDao {
/**
* Persists room.
*
* @param room object to persist
*/
void saveOrUpdate(Room room);
/**
* @param room object to remove from DB
*/
void delete(Room room);
/**
* @return the full room list
*/
List<Room> findAll();
/**
* @param name the searched name, must be case sensitive and exact match.
* Null name returns null result
* @return the room or null if nothing found
*/
Room findByName(final String name);
}
Java Persistence Query Language : JPQL¶
JPQL permet de créer des requêtes de recherche d'objets (aussi nommé entités) persistantes indépendamment du mécanisme utilisé pour stocker ces entités.
JPQL est donc portable et non limité à un type de base de données particulier.
JPQL est conçu pour combiner la syntaxe et la simplicité sémantique des requêtes SQL aux caractéristiques propres à Java.
L'implémentation des méthodes utilise des requêtes en JPQL (Java Persistence Query Language) 14. Ce langage, est très proche de SQL, sauf qu'il utilise le nom des classes/attributs. Ainsi le programmeur n'a pas à connaître les noms des tables et des colonnes pour écrire une requête.
Afin d'éviter d'écrire en dur les noms des attributs (et de générer des requêtes erronnées), un plugin Maven génère du code Java de description des tables afin d'utiliser des constantes générées et vérifiables à la compilation 15 pour nommer les tables, colomnes , ... .
Donc à chaque modification de la structure d'une Entity, il faut mettre à jour les méta-données : (c'est à dire recompiler via Maven le projet). Par exemple,
Room.class.getName()est la table associée à la classeRoom.Room_.name.getName()est le nom de la colonne correspondant à l'attribut "name" de la table associée à la classeRoom.
/**
* @param name of the room
* @return the corresponding room or null if nothing found
*/
@Override
@Transactional
public Room findByName(final String name) {
StringBuilder query = new StringBuilder("from ");
query.append(Room.class.getName()).append(" as room");
query.append(" where room.").append(Room_.name.getName());
query.append(" = :name");
List<Room> resultList = em.get().createQuery(query.toString()).
setParameter("name", name).
getResultList();
if (resultList.size() > 0) {
logger.debug("Room with name '{}' found", name);
return (Room) resultList.get(0);
}
logger.debug("No room with name '{}' found", name);
return null;
}
Enfin, l'utilisation de PreparedStatement (requêtage paramétré) offre de multiples avantages :
- cachabilité des plans d'exécution par les (gros) moteurs de base de données (Oracle, Postgres, etc.)
- insensibilité au risque d'attaque par injection SQL16 avec l'échappement automatique des paramètres
Exercice
Objectif : Maîtriser le pattern DAO et les fonctions JPA, avoir des notions de JPQL. Ajouter une nouvelle entité AccessEvent afin de gérer les entrées/sorties dans une salle.
- Ajouter dans roomDao la fonctionnalité de destruction d'un enregistrement removeRoom(String name); ainsi les 4 opérations de CRUD seront implémentés.
- Ajouter la commande dans l'application pour détruire un salle;
- compléter le code de la méthode createRoom de la classe App : tester l'unicité des noms de salle;
- Modifier temporairement le hibernate.hbm2ddl.auto pour les besoins du développement;
- Développer la classe AccessEvent * ajouter une attribut d'identification auto-généré * ajouter un attribut de nom de personne * ajouter un attribut de type d'évènement (entrée/sortie) * ajouter un attrivut de data/heure d'évenement * la relation vers Room est unidirectionnelle et elle est de type many-to-one
- Ajouter la commande dans l'application pour déclarer une entrée dans une salle;
- Ajouter la commande dans l'application pour déclarer une sortie d'une salle;
- Ajouter la commande de visualisation du journal des entrées/sorties d'une salle.
- Réaliser une fonction qui affiche tous les movements d'une personne (désignée par son nom).
Aspects non abordés¶
JPA est une norme très complète et un TD de 4 heures est largement insuffisant pour la couvrir en totalité. Ainsi, on peut citer quelques points afin de se faire une idée :
- Les caches de premier et second niveaux (et les problématiques associées en cluster) - La gestion de la concurrence - La gestion du versionning des entités - La gestion des Callbacks - L'utilisation des intercepteurs - L'intégration avec les fonctionnalités natives de certaines base de données (trigger, etc.)
Finalisation du projet room manager¶
Exercice
Objectif : Maîtriser les outils d'aide à la gestion de qualité du logiciel.
- Modifiez votre code pour ne plus générer d'erreur dans FindBugs, PMD et checkstyle. Le code fourni a déjà des erreurs détectées par ces outils, il faut aussi les corriger.
- Maximisez la couverture de tests.
À retenir (non exhaustif)¶
- Usage, contenu, structure, et réalisation d'un livrable via Maven.
- Patron de conception DAO (Data Acces Object).
- Usage de JPA pour construire la structure d'une base de données. Par exemple, savoir écrire la classe Building et modifier la classe Room (dont les objets seront enregistés dans la base de données) à l'aide des annotations JPA. Un building a une adresse (chaîne de moins de 500 caractéres alphanumériques), un nombre d'étages et il contient des pièces (Room). La relation entre building et Room est bidirectionnelle. L'annotation permettant de valider l'adresse d'un immeuble est aussi à écrire. Qu'elles sont les modifications à faire dans le fichier persistence.xml ?
- Des notions de JPQL. Par exemple savoir écrire la requête paramétrée suivante en JPQL "lister les building ayant au moins X étages" à l'aide de la requête JPQL suivante :
- Utilité/usage de JPA, ORM, JPQL, ...
- Des connaissances sur les composants utilisés :
slf4j,h2,common CLI,Google Guice. - Connaissance du rôle des fichiers binary.xml, persistence.xml et lockback.xml.
- Architecture logiciel (métier, dao, contrôle, IHM)
- Connaissance du rôle de la classe com.google.inject.persist.UnitOfWork et des annotations @Transactional, @Inject ...
Ressources supplémentaires¶
-
http://maven.apache.org/plugins/maven-assembly-plugin/ ↩
-
http://maven.apache.org/plugins/maven-assembly-plugin/assembly.html ↩
-
http://maven.apache.org/plugins/maven-site-plugin/ ↩
-
http://commons.apache.org/proper/commons-cli/ ↩
-
http://www.h2database.com/html/main.html ↩
-
http://www.oracle.com/technetwork/java/javase/jdbc/index.html ↩
-
http://docs.oracle.com/javaee/7/api/javax/persistence/EntityManager.html ↩
-
http://docs.oracle.com/javaee/7/api/javax/persistence/OneToOne.html ↩
-
http://docs.oracle.com/javaee/7/api/javax/persistence/OneToMany.html ↩
-
http://docs.oracle.com/javaee/7/api/javax/persistence/ManyToOne.html ↩
-
http://docs.oracle.com/javaee/7/api/javax/persistence/ManyToMany.html ↩
-
http://martinfowler.com/eaaCatalog/unitOfWork.html ↩
-
http://www.oracle.com/technetwork/java/dataaccessobject-138824.html ↩
-
https://docs.oracle.com/html/E24396_01/ejb3_langref.html ↩
-
https://docs.jboss.org/hibernate/jpamodelgen/1.0/reference/en-US/html_single/ ↩
-
http://fr.wikipedia.org/wiki/Injection_SQL ↩