====== TP JDBC, XML et TrAX ====== === Mises à jour === * **2011-10-06:** Ajout de quelques détails dans la partie génération de XML dans PostgreSQL. Bugfix sur etudes.xsd: le targetnamespace mal pris en charge -> on l'enlève. * **2011-10-04:** {{:enseignement:tp:bd:mif18-tp-base.zip|zip du dépôt}} en cas de problème avec la forge * **2011-10-04:** Changement des fichiers ''etudes.xsd'' et {{:enseignement:tp:bd:data-tp-bdav-univ.sql|script SQL}} contenant les données. === Remarques préalables === * Environnement de travail: on se placera dans le même environnement que pour le [[tp-orm2|TP ORM]] * Ce TP est à rendre pour le mardi **11/10**. Les modalités de rendu sont les mêmes que pour le [[tp-orm2|TP ORM]]. Il est possible de rendre les deux TPs simultanément, en particulier en cas de rendu via la forge. Les deux TPs sont cependant indépendants. ===== Introduction ===== L'objectif de ce TP est de pratiquer trois APIs: * l'API SQL de génération de XML, disponible, entre autres, sous PostgreSQL, Oracle, SQLServer ou DB2; * l'API JDBC permettant d'exécuter des requêtes sur un SGBD depuis du code Java; * l'API TrAX permettant de transformer des documents XML en Java. Pour ce TP, on utilisera une base PostgreSQL et le schéma du [[tp-orm2|TP ORM]]. On pourra utiliser le script fourni ci-dessous pour ajouter des données dans la base. === Quelques liens === * [[http://download.oracle.com/javase/6/docs/api/|API J2SE 6]] -> packages ''java.sql'', ''javax.xml.transform.*'' * Un [[tp-xml-sql|ancien TP]] sur la génération de XML en SQL, ainsi qu'un [[enseignement:bdav:old:tp-jdbc|TP sur JDBC]] et [[tuto-jdbc|un début de tutoriel]] * La [[http://www.postgresql.org/docs/8.4/static/functions-xml.html|documentation PostgreSQL sur les fonctions SQL/XML]] * La [[http://jdbc.postgresql.org/documentation/publicapi/index.html|javadoc du pilote PostgreSQL]] ===== Mise en place ===== {{:enseignement:tp:bd:data-tp-bdav-univ.sql|Script SQL}} pour ajouter quelques données, il est également possible d'en ajouter en utilisant le [[tp-orm2|TP ORM]]. Le dépôt utilisé pour le tp précédent contient un nouveau projet maven: ''tpxml''. Vous pouvez le récupérer: * soit en exécutant hg pull https://forge.univ-lyon1.fr/hg/mif18-tp-base depuis un répertoire dans le dépôt cloné pour le [[tp-orm2|TP ORM]] * soit en clonant à nouveau le dépôt dans un autre endroithg clone https://forge.univ-lyon1.fr/hg/mif18-tp-base ===== Travail demandé ===== Remarque: * Par "test", on entend test [[:enseignement:aide:apis#junit|JUnit]]. ==== Connexion JDBC ==== Écrire une classe ''bdav.jdbc.FournisseurConnexion'' ayant une méthode ''java.sql.Connection createConnection()'' renvoyant une connection JDBC à la base PostgreSQL. Écrire un test ''bdav.jdbc.JDBCTest'' qui teste cette méthode, puis ferme la connection((méthode ''close()'')). La méthode de test, ''testConnexion()'' devra être vide. On mettra le code de connexion dans ''setUp()'' et la fermeture de la connexion dans ''tearDown()''. * Des exemples de code JDBC peuvent être trouvés dans l'ancien [[enseignement:bdav:old:tp-jdbc|TP JDBC]] et [[tuto-jdbc|ici]]. * La classe ''DataSource'' PostgreSQL est ''org.postgresql.ds.PGSimpleDataSource''. Considérer les méthodes suivantes pour la configuration d'une telle DataSource ([[http://jdbc.postgresql.org/documentation/publicapi/index.html|javadoc]]): * ''void setServerName(String serverName)'' * ''void setDatabaseName(String databaseName)'' * ''void setUser(String user)'' * ''void setPassword(String password)'' ==== Requête simple ==== Écrire un test ''void testRequeteSimple()'' dans ''JDBCTest'' qui utilise une connexion fournie par FournisseurConnexion pour exécuter une requête renvoyant le nombre de département et qui teste la valeur du résultat. * Exemples de code dans le [[enseignement:bdav:old:tp-jdbc|TP JDBC]] * Ne pas hésiter à utiliser pgAdmin3 pour mettre au point la requête * La classe ''TestCase'', fourni des méthodes pour tester des valeurs comme ''assertEquals'' ([[http://www.junit.org/junit/javadoc/3.8.1/|javadoc JUnit]]) * Pour exécuter une requête, on peut s'inspirer du code suivant: Statement stat = connection.createStatement(); ResultSet rs = stat.executeQuery("SELECT toto, titi FROM bla bla"); while(rs.next()) { ... rs.getString("toto") ... ... rs.getInt("titi") ... } ==== Requête paramétrée ==== Écrire un test ''void testRequeteParametree()'' dans ''JDBCTest'' avec la requête précédente à laquelle on ajoute: WHERE nom = ? Au lieu d'utiliser un ''Statement'', on utilisera un ''PreparedStatement''. Le test exécutera deux fois requête avec des valeurs différentes pour le paramètre, mais sans créer de nouveau PreparedStatement entre les deux requêtes. * Exemples de code dans le [[enseignement:bdav:old:tp-jdbc|TP JDBC]] * Ne pas hésiter à utiliser pgAdmin3 pour mettre au point la requête, mais en remplaçant le ''?'' par une vraie valeur. * Pour exécuter la requête paramétrée, on peut s'inspirer du code suivant: PreparedStatement stat = connection.prepareStatement("SELECT toto, titi FROM bla bla ... AND nom = ? AND ..."); stat.setString(1,"Informatique"); ResultSet rs = stat.executeQuery(); while(rs.next()) { ... rs.getString("toto") ... ... rs.getInt("titi") ... } stat.setString(1,"DEVU"); rs = stat.executeQuery(); ... ==== Génération de XML par PostgreSQL ==== Ouvrir et comprendre le schéma XML ''[[http://forge.univ-lyon1.fr/projects/mif18-tp-base/repository/entry/tpxml/src/main/resource/etudes.xsd|tpxml/src/main/resources/etudes.xsd]]''. Consulter le [[tp-xml-sql|TP SQL/XML]], ainsi que la [[http://www.postgresql.org/docs/8.4/static/functions-xml.html|documentation sur les fonctions XML de PostgreSQL]]. Mettre au point une requête SQL construisant le bulletin d'un(e) étudiant(e) particulier(ère). Une fois au point, le code SQL de la requête et des éventuelles vues crées sont à placer dans le fichier ''tpxml/src/main/resources/etudes.sql''. * La création de vues intermédiaires est fortement recommandée: on peut par exemple faire une vue générant les éléments xml ''ue'', une vue générant les éléments ''semestre'' et enfin une vue générant le bulletin de chaque étudiant. * Les vues crées ne doivent pas dépendre de l'étudiant(e) choisi(e)((i.e. il ne doit pas y avoir une clause WHERE etudiant = 123456123, mais l'attribut etudiant doit apparaitre dans le résultat des vues. Il faut bien sur garder les égalité nécessaires au jointures dans le WHERE)). * Le schéma xsd peut être ouvert depuis Eclipse qui en fournira un aperçu graphique. * Le schéma xsd n'impose pas d'espace de nommage pour les documents correspondants. ==== Validation du XML produit ==== Consulter la documentation des classes ''javax.xml.validation.SchemaFactory'', ''Schema'' et ''Validator''. Consulter également la documentation de la classe ''java.sql.SQLXML''. Créer une classe (pas un test) ''bdav.xml.XMLReports'', ayant un champ de type ''java.sql.Connection'' pour exécuter des requêtes, ainsi qu'une méthode ''protected javax.xml.transform.Source getBulletin(long numEtudiant)'' récupérant le bulletin de l'étudiant au format XML. Ecrire un test ''bdav.xml.XMLReportsTest'' qui vérifie que le résultat renvoyé par getBulletin((pour un étudiant particulier)) est conforme au schéma ''tpxml/src/main/resources/etudes.xsd''. * En cas d'erreur du driver (''SQLFeatureNotSupportedException'') on utilisera ''getBinaryStream(...)'' à la place de ''getSQLXML(...)''. * Cette question combine les deux précédentes. * Il peut être utile de jeter un coup d'oeil aux {{:enseignement:bdav:apis-xml.pdf|transparents sur les APIs XML Java}}, en particulier sur la partie TrAX. * Il est possible de récupérer un flux binaire avec le contenu du schéma viagetClass().getResourceAsStream("/etudes.xsd"); ==== Application ==== Créer une feuille de style ''tpxml/src/main/resources/etudes-html.xsl'' permettant de faire une présentation xhtml d'un bulletin. Changer le code de la méthode ''main'' de la classe ''App'' pour que le programme affiche sur la sortie standard la version html du bulletin de l'étudiant dont on passe le numéro comme premier argument de la ligne de commande.