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: zip du dépôt en cas de problème avec la forge
  • 2011-10-04: Changement des fichiers etudes.xsd et script SQL contenant les données.

Remarques préalables

  • Environnement de travail: on se placera dans le même environnement que pour le TP ORM
  • Ce TP est à rendre pour le mardi 11/10. Les modalités de rendu sont les mêmes que pour le 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 ORM. On pourra utiliser le script fourni ci-dessous pour ajouter des données dans la base.

Quelques liens

Mise en place

Script SQL pour ajouter quelques données, il est également possible d'en ajouter en utilisant le 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 ORM

  • soit en clonant à nouveau le dépôt dans un autre endroit
    hg clone https://forge.univ-lyon1.fr/hg/mif18-tp-base

Travail demandé

Remarque:

  • Par “test”, on entend test 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 connection1). 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 TP JDBC et ici.
  • La classe DataSource PostgreSQL est org.postgresql.ds.PGSimpleDataSource. Considérer les méthodes suivantes pour la configuration d'une telle DataSource (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 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 (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 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 tpxml/src/main/resources/etudes.xsd. Consulter le TP SQL/XML, ainsi que la 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)2).
  • 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 getBulletin3) 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 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 via
    getClass().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.

1)
méthode close()
2)
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
3)
pour un étudiant particulier