Nicolas Mérat - Centre Universitaire d`Informatique
Transcription
Nicolas Mérat - Centre Universitaire d`Informatique
Nicolas Mérat Professeur G. Falquet automne 2001 Département de Système d’Information Stockage de données multimédias et conception de présentations dynamiques avec SMIL et Lazy Table de matières 1. Introduction..................................................................................................................... 4 2. Objectifs du travail .......................................................................................................... 4 3. Outils utilisés .................................................................................................................. 5 3.1 SMIL (Synchronized Multimedia Integration Language) ............................................... 5 3.1.1 Généralités ............................................................................................................ 5 3.1.2 Caractéristiques..................................................................................................... 6 3.1.3 Structure d’un document SMIL............................................................................... 6 3.1.4 Les principaux players SMIL .................................................................................. 9 3.2 Oracle et les LOBs ..................................................................................................... 10 3.2.1 Généralités .......................................................................................................... 10 3.2.2 Le type BLOB ...................................................................................................... 10 3.2.3 Le type BFILE ...................................................................................................... 11 3.2.4 Manipulation de BLOB ......................................................................................... 11 3.2.4.1 Fonctionnement du type BLOB...................................................................... 11 3.2.4.2 Exemple de création de table contenant le type BLOB.................................. 12 3.2.4.3 Exemple d’initialisation et d’écriture d’un BLOB............................................. 12 3.2.4.4 Exemple de lecture d’un BLOB...................................................................... 13 3.2.5 Manipulation de BFILE......................................................................................... 14 3.2.5.1 Fonctionnement du type BFILE ..................................................................... 14 3.2.5.2 Exemple de création de table contenant le type BFILE ................................. 15 3.2.5.3 Exemple de création de répertoire................................................................. 15 3.2.5.4 Exemple de création d’un BFILE ................................................................... 15 3.2.5.6 Exemple de lecture d’un BFILE ..................................................................... 16 3.3 Servlet........................................................................................................................ 17 3.3.1 Généralités .......................................................................................................... 17 3.3.2 Servlet et formulaire............................................................................................. 18 3.3.3 Structure d’un servlet ........................................................................................... 18 3.3.4 Exemple d’utilisation de servlet ............................................................................ 19 3.4 Lazy ........................................................................................................................... 19 3.4.1 Généralités .......................................................................................................... 19 3.4.2 Fonctionnement ................................................................................................... 20 3.4.3 Création de nœuds .............................................................................................. 20 4. Solution ........................................................................................................................ 22 4.1 Choix du domaine ...................................................................................................... 22 4.2 Modélisation du domaine ........................................................................................... 23 4.2.1 Modèle relationnel ............................................................................................... 24 4.3 Liste des relations et création des différentes tables .................................................. 25 2 4.4 Insertion des données dans la base de données........................................................ 25 4.5 Conception d’un servlet pour la récupération des données ........................................ 26 4.5.1 Installation d’un serveur HTTP............................................................................. 26 4.5.2 Création du formulaire ......................................................................................... 26 4.5.3 Elaboration du servlet .......................................................................................... 27 4.5.4 Modification du fichier web.xml ............................................................................ 30 4.5.5 Vue d’ensemble ................................................................................................... 31 4.5.6 Exemple de requête............................................................................................. 31 4.6 Choix d’un player ....................................................................................................... 31 4.6.1 HTML+TIME ........................................................................................................ 32 4.6.1.1 Structure d’un document HTML+TIME .......................................................... 32 4.6.2 RealONE ............................................................................................................. 33 4.7 Installation de Lazy..................................................................................................... 33 4.8 Conception de nœuds SMIL en Lazy.......................................................................... 34 4.8.1 Modification du serveur de nœuds ....................................................................... 34 4.8.2 Conception de nœuds SMIL ................................................................................ 35 4.9 Présentation finale ..................................................................................................... 35 4.9.1 Détails des nœuds créés ..................................................................................... 35 4.9.2 Problèmes rencontrés.......................................................................................... 36 5. Conclusion.................................................................................................................... 36 6. Bibliographie................................................................................................................. 37 7. Annexes ....................................................................................................................... 38 3 1. Introduction Au cours de ces dernières années, il y a eu une prise de conscience générale du besoin et de l’utilité des technologies multimédias, ceci dans de nombreux domaines, comme la médecine et l’éducation. En effet, le multimédia améliore la qualité de l’information et fournit un meilleur moyen de la représenter et d’interagir avec elle. Ainsi, les applications multimédias enrichissent les applications existantes en intégrant des images, du son, ou encore de la vidéo. Ces différents types de données et leur manipulation apportent de nouveaux défis : par exemple, les bases de données doivent être remises à jour pour supporter ces différents types ; de même, les réseaux doivent réévaluer leurs besoins pour des bandes passantes plus flexibles et plus larges, et on peut par exemple voir l’importance du multimédia avec l’apparition de réseaux à large bande comme ATM, ISDN, ou encore ADSL. Je vais m’intéresser, dans un premier temps, au stockage de ces données multimédias. Les exigences de stockage sont élevées, et il est inconcevable de stocker toutes ces données localement. Ainsi, les bases de données multimédias offre une possibilité de stockage, mais aussi de partage et d’interrogation de ces différentes informations. Elles permettent de manipuler des données de type texte, image, son, vidéo, contrairement aux bases de données traditionnelles qui permettent seulement de manipuler des données numériques et des caractères. Ainsi, des fonctionnalités ont du être ajoutées dans les systèmes de gestion de base de données afin de permettre le stockage pour ces données qui peuvent être de taille considérable. De même, il a fallu étendre les langages d’interrogation comme SQL qui n’étaient pas appropriés pour les flux continus qui surviennent lors de la manipulation de données multimédias. Ensuite, je vais m’intéresser à la conception de présentations dynamiques à partir de données stockées dans une base de données multimédia. En effet, nombreuses sont les sources d’intérêt dans la création de présentations multimédias, comme par exemple les livres électroniques, les cours à distances ou encore les pages webs dynamiques ; de ce fait, plusieurs modèles et standards correspondant à ces besoins apparaissent, permettant de répondre à des questions du type : quels objets doivent être inclus dans la présentation ? à quel moment les objets doivent-ils être affichés ? où doivent apparaître les objets sur l’écran ? 2. Objectifs du travail L’ objectif final du travail est de pouvoir créer des présentations SMIL dynamiques à partir de diverses données multimédias – photos, vidéos, sons, textes – stockés dans une base de données, à l’aide du langage Lazy. Ces présentations doivent pouvoir interagir entre elles ; l’utilisateur doit pouvoir se « promener » dans l’information en suivant les liens qui l’intéressent. Différentes étapes intermédiaires sont nécessaires pour en arriver là, parmi lesquelles : • Comprendre SMIL et apprendre à utiliser ce langage • Trouver le(s) type(s) de donnée adéquat pour stocker des données multimédias dans une base de données 4 • Établir une connexion JDBC avec la base de données • Tester le(s) type(s) de données trouvé(s) pour le stockage des données multimédias, au moyen de JDBC • Stocker des données multimédias de manière « automatique » à partir de leur répertoire • Étudier les servlets afin d’un concevoir un permettant de récupérer une donnée multimédia et de l’envoyer sur le navigateur client • Comprendre Lazy et apprendre à utiliser ce langage (savoir créer des nœuds) • Trouver un domaine pour concevoir un exemple de présentation multimédia, ainsi que des données (photos, images, vidéos, sons) le concernant • Définir le modèle relationnel pour l’exemple de présentation : quelle(s) relation(s) et quel(s) attribut(s) choisir • Créer les différentes tables (d’après le modèle relationnel) 3. Outils utilisés 3.1 SMIL (Synchronized Multimedia Integration Language) 3.1.1 Généralités Une présentation multimédia est composé dans l’espace et dans le temps d’objets euxmêmes mono ou multimédias qui peuvent être de type continu (temporel) comme le son ou la vidéo ou de type discret (non temporel) comme l’image et le texte. Lors de la conception de la présentation vont se poser des problèmes de synchronisation entre les différents médias, et de prise en compte des dépendances spatio-temporelles. En effet, comment définir quel vidéo A doit se jouer à la suite de telle autre vidéo B, et à tel endroit dans la fenêtre de présentation ? Ou encore, comment définir qu’une séquence vidéo C doit commencer en même temps qu’un commentaire D ? C’est à ce genre de questions qu’ont tenté de répondre les membres du W3C (consortium mondial regroupant des industriels et des centres de recherche, dont l'objectif est de développer et promouvoir le Web) en proposant un format de documents multimédia nommé SMIL (Synchronized Multimedia Integration Language). L'objectif de ce format est de permettre à toute personne de spécifier les aspects temporels et visuels de documents multimédias tout en permettant à l’utilisateur d’interagir avec la présentation au moyen de liens hypertextes. On peut voir ce langage comme une extension du standard HTML (SMIL est un langage de balisage basé sur XML), qui permet de résoudre le problème de coordination et de synchronisation dans l’affichage de différents médias sur des sites webs, en utilisant une seule ligne temporelle. Du fait qu’elle est basée sur un langage de balisage, une présentation SMIL peut être créée avec un simple éditeur de texte pour tout outil. 5 3.1.2 Caractéristiques Une présentation SMIL possède les caractéristiques suivantes : • La présentation est composée de un ou plusieurs objets multimédias accessibles au moyen d’un URL ; les objets ne sont donc pas physiquement insérés dans le document SMIL et peuvent être de différents types de médias (son, vidéo, image, texte, animation). Ainsi, les composants peuvent être indépendants et se trouver sur différents serveurs webs (ils ne sont récupérés par l’application que lors de son exécution) ce qui permet de diviser le contenu multimédia en flux et fichiers séparés et de les jouer comme un seul et unique flux multimédia. De ce fait, la taille d’une présentation SMIL est assez réduite. • On peut définir le placement temporel ainsi que le placement géométrique des objets multimédias. On peut par exemple définir le temps de début et le temps de fin d’un média, ou encore sa durée. On peut également définir la présentation parallèle de deux ou plusieurs médias, ou la présentation en séquence. Un document SMIL possède une seule horloge pour tous ses composants, une seule ligne temporelle. • On peut associer des liens hypertextes aux différents composants multimédias ; l’utilisateur pourra donc suivre les liens placés dans la présentation et interagir avec cette présentation par le biais des liens proposés. Ainsi, deux utilisateurs visualisant la même présentation, et n’ayant pas les mêmes centres d’intérêt, pourront accéder aux informations qui les intéressent en suivant simplement les liens qui les concernent. • SMIL permet d’afficher le média selon les préférences de l’utilisateur et les capacités de son système. Il adapte donc la présentation à la bande passante de l’utilisateur, et à ses préférences linguistiques. Par exemple, l’auteur d’une présentation SMIL pourra indiquer quel fichier vidéo jouer selon la bande passante de l’utilisateur : « si la bande est supérieure à 56 kbits/s jouer zzz, sinon jouer xxx ». • La production d’une présentation multimédia avec SMIL ne requiert aucune compétence particulière en programmation. C’est un langage facile à apprendre, et pour créer et modifier des présentations multimédias, un simple éditeur de texte suffit. • SMIL utilise la technologie du streaming, c’est à dire qu’un média commence à être jouer sans avoir à attendre le téléchargement complet du fichier. Ainsi, par exemple, une application commence à jouer un son avant même qu’elle ait chargé la totalité du fichier. Cependant cette technique n’est possible que si le serveur web utilisé repose sur un protocole RSTP (Real-time Stream Transport Protocol), et non HTTP. 3.1.3 Structure d’un document SMIL Un document SMIL a pour racine l’élément <smil>, et se compose d’une en-tête et d’un corps. La partie <head> contient toutes les informations descriptives et relatives à la mise en page, alors que la partie <body> contient le corps du document, les informations sur les médias et sur leur comportement, la partie dynamique de la présentation. La structure type d’un document SMIL ressemble à ceci : <smil> <head> <meta/> 6 <layout> <root-layout/> <region/> </layout> </head> <body> <switch> … </switch> <par> … </par> <seq> … </seq> </body> </smil> A l’intérieur de la section <head>, nous avons une partie <meta> qui contient des informations descriptives, comme l’auteur ou la date de conception de la présentation, et une partie <layout> qui définit le positionnement et la mise en page de la fenêtre dans laquelle va se jouer la présentation. Cette section contient elle-même deux types de balises. En premier lieu, la balise <root-layout> qui permet de définir les propriétés de la fenêtre de présentation, comme sa dimension et sa couleur de fond. Enfin, la balise <region> permet de définir des zones dans la fenêtre de présentation dans lesquelles les différents médias seront affichés ; chaque région doit avoir un identificateur, un emplacement, et peut avoir une couleur. Dans l’exemple suivant, deux régions sont définies, une pour le texte, et une pour l’image : <layout> <root-layout id="exemple" title="exemple" width="800" height="600"/> <region id="image" title="image" top="15" left="290"/> <region id="text" title="texte" top="270" left="290"/> </layout> La balise <body> et ses descendants permettent de placer les composants dans les régions définies dans l’élément <layout> décrit ci-dessus. Deux balises de base de cette section permettent de contrôler la ligne temporelle : <par> et <seq>. Les différents médias référencés dans un tag <par> sont joués en parallèle, simultanément. En revanche, les médias se trouvant à l’intérieur d’une balise <seq> sont joués en séquence, c’est-à-dire les uns après les autres. Il est possible d’imbriquer ces deux types de tag les uns dans les autres pour créer des sous-présentations. Dans l’exemple suivant, les images sont affichées en séquence (les unes à la suite des autres) mais en même temps qu’un texte descriptif : <body> <seq> <par> <text region="text" <img region="image" </par> <par> <text region="text" <img region="image" </par> </seq> </body> src="./media/text1.txt" dur="10s"/> src="./media/img1.gif" dur="10s"/> src="./media/text2.txt" dur="10s"/> src="./media/img2.gif" dur="10s"/> Maintenant, si on regarde plus précisément comment sont introduits les différents médias dans la présentation, on peut remarquer que chaque média possède sa propre balise. Ainsi sept éléments XML correspondant chacun à un type de média vont permettre de placer les composants dans une présentation. On distingue deux catégories de médias : les médias continus qui ont une durée intrasèque (son, vidéo) et les médias discrets qui n’ont pas de durée prédéfinie (images, texte) mais qui pourront en avoir une dans le cadre de la présentation. Les différentes balises sont les suivantes : 7 <audio> pour les composants sonores (voix, son …) <video> pour les séquences vidéos <textstream> pour les textes dynamiques, avec déroulement automatique, par exemple <animation> pour les animations, en Flash par exemple <ref> pour tout média continu qui n’est pas compris dans un des types ci-dessus <img> pour des images <text> pour des composants textuels Pour tous ces différents tags, l’attribut src permet de spécifier l’emplacement du média, qu’il se trouve dans le répertoire courant ou sur un serveur web distant, et l’attribut region permet de définir l’emplacement dans lequel le média va se jouer (cet emplacement doit avoir été créé préalablement, voir partie <head>) . Il est important de noter qu’à l’intérieur de balises <par> ou <seq> le temps se déroule de manière automatique ; en effet, un média référencé dans un tag <seq> va se jouer directement à la suite de celui qui le précède. Cependant, si l’auteur de la présentation veut contrôler lui-même la ligne temporelle, il est possible de définir le début, la fin ou la durée d’un média. Tous les intervalles de temps sont mesurés par rapport à la ligne temporelle de SMIL, qui est propre à l’application de présentation. C’est l’utilisateur qui la contrôle : il a le choix de jouer la présentation, de la faire revenir en arrière, de l’avancer ou encore de la stopper. Voici la syntaxe permettant de définir des durées en SMIL : - 15s = 15 secondes 2.5h = 2 heures 30 minutes 1.5 min = 1 minute 30 600 ms = 600 millisecondes Dans l’exemple suivant, les médias sont un texte et une image qui se trouvent sur un serveur web (HTTP) ; l’image apparaît dans une région appelée image et définie dans la partie <head> du document, de même, le texte apparaît dans une région appelée text. La durée de présentation de chaque média est de 10 secondes : <par> <text region="text" src="http://localhost:8080/media/text1.txt" dur="10s"/> <img region="image" src=" http://localhost:8080/media/img1.gif" dur="10s"/> </par> La balise <switch> permet de définir plusieurs options parmi lesquelles le player SMIL en choisira une lors de l’exécution. Ainsi, on peut inclure plusieurs fichiers sons dans une présentation, et celui qui sera jouer sera définit par les préférences linguistiques de l’utilisateur. De même, on peut inclure plusieurs images de différentes résolution qui seront jouées selon la bande passante de l’utilisateur. A l’exécution, dès qu’une option est évaluée à "vrai", elle est choisie et on sort du <switch> ; pour cette raison, il est important de définir les élément dans l’ordre de préférence, en commençant par ceux qui offrent la présentation de la meilleure qualité. Par exemple, on peut jouer un fichier son différent en fonction de la vitesse de la connexion : <switch> <audio src="manu_chao.mp3" system-bit-rate="56000"/> <audio src="noir_desir.mp3"/> </switch> Jusqu’à maintenant, il n’y a pas d’interaction possible pour l’utilisateur, ce dernier est passif. Mais une présentation multimédia n’est pas une simple animation que l’on doit regarder, elle offre à l’utilisateur un choix d’itinéraire dans son déroulement au moyen de liens hypertextes. Un lien définit dans une présentation SMIL peut être défini sur tout type de média, et peut 8 renvoyer à une autre présentation, à un autre point d’entrée dans la présentation, à une page HTML … Deux balises peuvent être utilisées pour définir un lien sur un média : <a> et <anchor>. L’élément <a> correspond à celui du même nom présent en HTML avec un attribut supplémentaire permettant de contrôler la présentation lorsque le lien est activé. Ainsi, la présentation cible peut remplacer la présentation source ou peut être démarrée dans une nouvelle fenêtre ; de même, si la présentation cible commence dans une nouvelle fenêtre, la présentation source peut continuer de se jouer ou être arrêtée. Cet exemple nous montre comment placer un lien sur une image ; lien qui s’ouvrira dans une nouvelle fenêtre et arrêtera la présentation : <a href="exemple.smi" external="true" sourcePlaystate="pause"> <img region="image" src="./media/img1.gif" dur="10s"/> </a> La balise <anchor> (renommée <area> en SMIL 2.0) permet, quand à elle, d’associer des liens sur des parties d’un média ; par exemple, le coin supérieur gauche d’une image possède un lien vers une page HTML, et le coin inférieur droit possède un lien vers une autre présentation SMIL. De plus, cette balise permet d’associer des liens selon des intervalles de temps ; par exemple, un lien est associé à une image pendant les dix première secondes de présentation, alors qu’un autre lien est associé pendant le reste de la présentation. Dans l’exemple suivant, un lien est associé seulement avec une partie (rectangulaire) de l’image : <img region="image" src="./media/img1.gif" dur="10s"> <area shape="rect" coords="0,0,50,50" href="exemple.smi"/> </img> Je viens de présenter les bases nécessaires à la conception d’un document SMIL, mais pour plus de détails je vous conseille vivement d’aller voir toutes les possibilités offertes par SMIL sur le site du W3C. Il est bon de savoir, que le W3C a sorti une nouvelle recommandation de SMIL (nommée SMIL 2.0) en août dernier. La grande nouveauté de SMIL 2.0 provient de l’introduction d’un module d’animation qui permet de bouger et de donner des effets aux divers médias apparaissant dans une présentation SMIL. Cependant, à l’heure actuelle, et vu la nouveauté de SMIL 2.0, un nombre très restreint de players supportent ce langage. 3.1.4 Les principaux players SMIL Les players ne supportent pas tous complètement les spécifications de SMIL, et il est bon de tester sa présentation SMIL dans différents players car elle peut se jouer sans problème dans certains, et ne pas se jouer du tout dans d’autres ! ! ! SMIL 1.0 : - GriNS, d’Oratrix QuickTime 4.1, d’Apple RealPlayer 8, de RealNetworks Soja, applet java conçue par Helio SMIL 2.0 : - RealONE, de RealNetworks GriNS, d’Oratrix Internet Explorer 5.5 et 6, de Microsoft 9 3.2 Oracle et les LOBs 3.2.1 Généralités Les bases de données multimédias permettent le partage, l’accès, et l’interrogation de grandes collections d’informations multimédias. Ainsi, le second outil utilisé est un système de gestion de bases de données – Oracle – pour stocker les données utilisées dans les présentations multimédias. Une fois le système de gestion de bases de données choisi, il faut regarder quel(s) sont le(s) type(s) de données adéquat(s) pour stocker des photos, ou tout autre type de données multimédias. A partir de sa version 8, Oracle fournit un certain nombre de types de données qui supportent le stockage de grandes quantités d’information – jusqu’à quatre gigabytes – tel que texte, images, vidéo, et son. Ces Larges Objets (ou LOBs) sont stockés soit dans la base, ce sont alors des LOBs internes, soit dans un fichier externe, ce sont des LOBs externes. Ces différents types LOBs sont utilisés pour les données qui sont trop grandes pour être stockées directement dans une table de la base de données ; de ce fait, un locator (un pointeur logique) est stocké dans la table et pointe sur l’emplacement des données, qu’elles soient à l’intérieur, ou hors de la base de données. Comme nous le verrons par la suite, toutes les manipulations de LOBs se font à travers de streams java. Pour stocker des données multimédias dans les versions précédentes d’Oracle, il existe diverses manière de faire. Soit il faut utiliser le type Long Raw qui permet de stocker des données binaires de forme quelconque ; cependant, les données déclarées ainsi ne peuvent pas être indexés, ni affichées, ni même interrogées au moyen de SQL*Plus. Soit il faut référencer chaque image en stockant son URL dans la base. Il est facile de voir comment la présence des différents médias est devenue prépondérante dans les applications actuelles, et les concepteurs d’Oracle s’en sont très bien rendus compte en permettant ce stockage de données binaires de taille variable. Prenons l’exemple d’un professeur qui pourrait enregistrer des versions audio des cours qu’il doit donner, et les stocker dans la base, tout comme les présentations qui les accompagnent. Le jour du cours (ou la veille), il pourrait récupérer un certain nombre de ces données dans un fichier SMIL (au moyen d’un langage comme LAZY), et mettre son cours en ligne, sa présence en classe n’est même pas indispensable ! ! ! Je vais seulement m’attarder sur les deux types de LOBs qui conviennent particulièrement pour le stockage de données multimédias – ou pour tout autre type de données binaires nonstructurées – en laissant de côté le type permettant le stockage de textes (les CLOBs). Deux types de données conviennent particulièrement : les BLOBs qui sont des LOBs internes et les BFILEs qui sont des LOBs externes. 3.2.2 Le type BLOB Permet de stocker des données binaires brutes (non structurées) dont la taille ne dépasse pas les 4 gigabytes. Les données sont stockées dans la base de données, ce qui permet d’optimiser l’espace et de fournir un accès plus rapide à ces dernières. Les données BLOB sont accédées et référencées au moyen d’un pointeur logique qui est stocké dans la table de la base de données et qui pointe vers les données. 10 3.2.3 Le type BFILE Permet de stocker un fichier binaire dans un fichier externe à la base de données Oracle (sur disque dur, CDROM, CdPhoto, …). Le fichier peut avoir une taille maximale de 4 gigabytes également. Une colonne ou un attribut BFILE stocke un locator de fichier qui pointe vers le fichier externe contenant les données. L’accès aux données n’est possible qu’en lecture, il n’est donc pas possible de modifier un BFILE. Le système d’exploitation sous-jacent doit maintenir la durabilité et l’intégrité du fichier ; l’administrateur de la base de données doit assurer que le fichier existe et que les divers processus Oracle ont la permission de lire le fichier. 3.2.4 Manipulation de BLOB Cette section décrit comment utiliser JDBC, et plus particulièrement les classes de oracle.sql.* pour travailler avec les BLOBs. En effet, les principales méthodes permettant la lecture et l’écriture de données BLOBs sont définies dans le package oracle.sql.* (téléchargeable sur le site d’Oracle), tout comme la plupart des méthodes permettant la manipulations de données BFILEs, qui sont le sujet de la prochaine section. Pour que le compilateur java trouve ce package, il est nécessaire de le définir dans le classpath (SET CLASSPATH=k:\memoire\oracle817\classes12.zip). 3.2.4.1 Fonctionnement du type BLOB Pour travailler avec des données BLOBs, on doit tout d’abord obtenir leur locator (sorte de pointeur logique); ensuite, il est possible de lire des données ou d’écrire des données dans un BLOB, et d’effectuer toutes sortes de manipulations sur ces données. Le locator, équivalent d’un pointeur en programmation, est stocké dans la table de la base. Ainsi, lors de chaque nouvelle entrée dans la table – après avoir préalablement créé la table contenant un attribut de type BLOB – il faut initialiser la valeur du BLOB à « vide », ce qui va créer le locator du BLOB ; ensuite seulement on pourra insérer la donnée multimédia au moyen de son locator. On peut récupérer le pointeur du BLOB grâce à la méthode getBLOB() ; en effet, le résultat fourni par une requête SELECT nous renvoie le locator et non pas directement les données binaires. Une fois que l’on a le pointeur logique, on peut lire et écrire les données BLOBs au moyen de JDBC. Les données BLOBs sont représentées sous forme de streams java ; contrairement aux principaux streams, il est possible d’accéder aux données à n’importe quel moment durant la connexion du fait que le locator des données BLOBs est stocké dans la table. Pour lire des données, on utilise tout d’abord la méthode getBinaryStream() pour récupérer le BLOB sous forme de stream, puis on utilise la méthode read() pour le lire. De même, pour écrire un BLOB, on utilise tout d’abord la méthode getBinaryOutputStream() pour le récupérer sous forme de stream de sortie, puis on utilise la méthode write() pour l’écrire. A noter que la méthode write() écrit directement dans la base de données lorsque l’on écrit sur le stream de sortie : il n’est pas nécessaire d’exécuter un UPDATE/COMMIT pour écrire les données. De même, la suppression d’un BLOB supprime à la fois les données BLOBs et leur pointeur logique. Pour illustrer ces explications je vais expliquer chacune des différentes étapes au moyen d’un exemple. Tous les exemples suivants sont des méthodes qui peuvent être appelées dans le code de la connexion [7], après la création de la connexion, et avant sa fermeture, bien entendu. 11 3.2.4.2 Exemple de création de table contenant le type BLOB Je n’ai créé qu’une seule table, nommée MULTIMEDIA, avec comme clé primaire un numéro (No_Blob) qui est incrémenté à chaque nouvelle entrée dans la table. Les autres attributs sont le nom, la description, le type de la donnée multimédia, et bien sûr la donnée ellemême. A noter que le type est le type MIME ; par exemple, si l’on insère une image jpeg dans la base de données, son type sera image/jpeg. private void creerTableBlob(){ try{ Statement stmt=conn.createStatement(); stmt.execute("create table MULTIMEDIA(No_blob Number(5) not null primary key, Nom Varchar2(80), Donnee Blob, Description Varchar2(500), Type Varchar2(50))"); stmt.close(); } catch(SQLException e){ System.out.println("requete ERROR: "+e.getMessage()+e.getSQLState()+e.getErrorCode()); } } NB : Lorsque l’on définit un attribut de type BLOB dans une table, on peut spécifier les différentes caractéristiques de stockage de l’objet. 3.2.4.3 Exemple d’initialisation et d’écriture d’un BLOB Cet exemple montre comment insérer dans un BLOB un fichier passé en paramètre, fichier qui doit se trouver dans le répertoire courant. Tout d’abord, on récupère le nom du fichier ainsi que le plus grand identificateur de BLOB (No_blob) présent dans la table, que l’on incrémente de un. private void insererUnBlob(File fichier){ try{ Statement stmt=conn.createStatement(); ResultSet result=stmt.executeQuery("SELECT max(No_blob) from MULTIMEDIA"); int test=0; String name=""; String typ="none"; name=fichier.getName(); if(result.next()){ test=result.getInt(1); } result.close(); test=test+1; Puis, on regarde l’extension du fichier grâce à son nom, ce qui va nous permettre de définir son type MIME. Ainsi, pour un fichier dont l’extension commence par j (pour jpeg) sont type sera : image/jpeg. for(int z=0;z<name.length();z++){ if(name.charAt(z)=='.'){ if((name.charAt(z+1)=='j')||(name.charAt(z+1)=='J')) typ="image/jpeg"; if((name.charAt(z+1)=='g')||(name.charAt(z+1)=='G')) 12 typ="image/gif"; … break; } } Ensuite, on insère une nouvelle entrée dans la table avec ces différentes données, tout en initialisant la valeur du BLOB à « vide » au moyen de empty_blob(), ce qui va créer son locator. stmt.execute("INSERT INTO MULTIMEDIA values ('"+test+"','"+name+"',empty_blob(),null,'"+typ+"')"); Finalement, on récupère la valeur du locator du BLOB créé grâce à une requête SQL du type SELECT et à la méthode getBLOB(), puis on ouvre un stream de sortie sur ce dernier (OutputStream) dans lequel on écrit le fichier, qui a préalablement été ouvert sous forme de stream (InputStream). Les méthodes read() et write() sont utilisées pour la lecture et l’écriture, et la taille du buffer idéale est déterminée grâce à la méthode getChunkSize() ; une fois l’écriture complète, on ferme les deux streams. ResultSet results=stmt.executeQuery("SELECT Donnee FROM MULTIMEDIA WHERE No_blob='"+test+"' FOR UPDATE"); //on prend le locator du blob if(results.next()){ BLOB blobloc=((OracleResultSet)results).getBLOB(1); try{ InputStream entree=new FileInputStream(fichier); //on ouvre un stream de sortie pour le blob OutputStream sortie=blobloc.getBinaryOutputStream(); int chunk=blobloc.getChunkSize() ; byte[] buffer=new byte[chunk]; int nbread=0 ; //nombres de bytes lus while ((nbread=entree.read(buffer)) != -1) //lecture sortie.write(buffer,0,nbread); //ecriture entree.close(); sortie.close(); } NB : Il est bien sûr possible d’insérer tout un répertoire de données multimédias dans la base de données, en passant son nom en paramètre, et selon les mêmes procédés. 3.2.4.4 Exemple de lecture d’un BLOB Cet exemple montre comment récupérer un BLOB dont le nom est passé en paramètre, en le copiant dans un répertoire temporaire sous le même nom. Dans un premier temps, on récupère le nom et le locator du BLOB au moyen d’une requête SQL du type SELECT et aux méthodes getBLOB() et getString(). private void recupererUnBlob(String name){ try{ Statement stmt=conn.createStatement(); ResultSet results=stmt.executeQuery("SELECT Donnee,Nom FROM MULTIMEDIA WHERE Nom='"+name+"'"); //on prend le locator du blob if(results.next()){ BLOB blobloc=((OracleResultSet)results).getBLOB(1); String n=results.getString(2); 13 Puis on ouvre un stream d’entrée sur ce dernier (InputStream) afin de permettre la lecture des données BLOBs, que l’on va écrire dans un fichier (FileOutputStream) qui porte le même nom que celui du BLOB, et qui va se trouver dans le répertoire C:\temp. Finalement, une fois l’écriture complète, on ferme les deux streams. Il ne nous reste qu’à regarder dans le répertoire temporaire pour vérifier que le fichier a bien été créé. try{ InputStream entree=blobloc.getBinaryStream(); FileOutputStream sortie=new FileOutputStream("C:\\temp\\"+n); int chunk=blobloc.getChunkSize() ; byte[] buffer=new byte[chunk]; int nbread=0 ; //nombres de bytes lus while ((nbread=entree.read(buffer)) != -1) //lecture sortie.write(buffer,0,nbread); //ecriture sortie.flush(); sortie.close(); entree.close(); } 3.2.5 Manipulation de BFILE Cette section décrit comment utiliser JDBC et les classes de oracle.sql.* pour travailler avec les BFILEs. 3.2.5.1 Fonctionnement du type BFILE Dans le cas des BFILEs, c’est également un locator qui se trouve stocké dans la base de données, mais celui-ci pointe vers un fichier externe à la base de données, stocké quelque part dans le système de fichiers. Ainsi, pour la lecture, on procède de la même manière que pour un BLOB : on récupère le pointeur logique au moyen d’une requête SQL du type SELECT, puis on ouvre un stream pour lire les données. Les BFILEs sont read-only : on ne peut donc pas insérer de données ni écrire dans un BFILE, ce qui est possible avec un BLOB (voir section précédente). Avant de définir un BFILE, il est donc nécessaire de s’assurer que le fichier que l’on veut référencer existe préalablement, et il faut créer un objet répertoire qui est un alias du chemin d’accès au fichier. Ainsi, lors de la création d’un BFILE, on doit spécifier le nom du fichier et le répertoire dans lequel le fichier se trouve ; il n’y a pas d’écriture des données dans la base de données. L’administrateur de la base de données doit s’assurer que la lecture est permise sur le fichier, et vérifier que les déplacements et/ou suppression de fichiers ne porte pas atteinte à l’intégrité de la base de données. Il est à noter que la plupart des méthodes applicables aux BFILEs, comme getDirAlias() et getName() ne nécessitent pas l’ouverture du fichier ; seules les méthodes permettant de le lire et de l’afficher requièrent son ouverture. A noter que la suppression d’un BFILE supprime seulement le pointeur logique, mais pas le fichier qui était référencé. Pour illustrer ces explications je vais expliquer chacune des différentes étapes au moyen d’un exemple. Tous les exemples suivants sont des méthodes qui peuvent être appelées dans le code de la connexion [7], après la création de la connexion, et avant sa fermeture, bien entendu. 14 3.2.5.2 Exemple de création de table contenant le type BFILE Comme dans le cas des BLOBs, je n’ai créé qu’une seule table, nommée PHOTO, avec comme clé primaire un numéro (No_bfile) qui est incrémenté à chaque nouvelle entrée dans la table. Les autres attributs sont similaires à ceux présents dans la table MULTIMEDIA. private void creerTableBfile(){ try{ Statement stmt=conn.createStatement(); stmt.execute("create table PHOTO(No_bfile Number(5) not null primary key, Nom Varchar2(80), Photo Bfile, Description Varchar2(500), Type Varchar2(25))"); stmt.close(); } catch(SQLException e){ System.out.println("requete ERROR: "+e.getMessage()+e.getSQLState()+e.getErrorCode()); } } 3.2.5.3 Exemple de création de répertoire Cet exemple montre comment définir le répertoire dans lequel le fichier se trouve ; ce répertoire est un alias du chemin d’accès au fichier. private void creerRepertoireBfile(){ try{ Statement stmt=conn.createStatement(); stmt.execute("CREATE OR REPLACE DIRECTORY img AS '/user/l1/merat7/memoire/multimedia'"); System.out.println("Repertoire cree..."); stmt.close(); } catch(SQLException e){ System.out.println("requete ERROR: "+e.getMessage()+e.getSQLState()+e.getErrorCode()); } } NB : A noter que le répertoire ainsi créé se nomme IMG et non pas img, car Oracle convertit tout en majuscules. De plus, pour pouvoir créer un répertoire, il faut avoir la permission CREATE ANY DIRECTORY de l’administrateur de la base de données ; de même pour supprimer un répertoire, il faut avoir la permission DROP ANY DIRECTORY. 3.2.5.4 Exemple de création d’un BFILE Cet exemple montre comment créer un BFILE d’un fichier passé en paramètre, fichier qui doit se trouver dans le répertoire définit au point précédent. Tout d’abord, on récupère le nom du fichier ainsi que le plus grand identificateur de BFILE (No_bfile) présent dans la table, que l’on incrémente de un. private void insererUnBfile(File fichier){ try{ Statement stmt=conn.createStatement(); ResultSet result=stmt.executeQuery("SELECT max(No_bfile) from PHOTO"); int test=0; 15 String name=""; String typ="none"; name=fichier.getName(); if(result.next()){ test=result.getInt(1); } result.close(); test=test+1; Puis, on regarde l’extension du fichier grâce à son nom, ce qui va nous permettre de définir son type MIME. Ainsi, pour un fichier dont l’extension commence par j (pour jpeg) sont type sera : image/jpeg. for(int z=0;z<name.length();z++){ if(name.charAt(z)=='.'){ if((name.charAt(z+1)=='j')||(name.charAt(z+1)=='J')) typ="image/jpeg"; if((name.charAt(z+1)=='g')||(name.charAt(z+1)=='G')) typ="image/gif"; … break; } } Enfin, on insère une nouvelle entrée dans la table avec ces différentes données. Il n’y a pas besoin d’ouvrir de streams d’entrée et de sortie car on n’écrit pas le fichier, on le référence; ainsi, la création d’un BFILE est beaucoup plus simple que celle d’un BLOB, elle s’effectue simplement au moyen de bfilename(’nom_répertoire’,’nom_donnee’). stmt.execute("INSERT INTO PHOTO values ('"+test+"','"+name+"',bfilename('IMG','"+name+"'),null,'"+typ+"')"); System.out.println("BFILE :"+name+" ok"); stmt.close(); } NB : Une conséquence de cette sémantique : il est possible d’avoir enregistrements BFILEs différents qui référencent tous le même fichier. plusieurs 3.2.5.6 Exemple de lecture d’un BFILE Cet exemple montre comment récupérer un BFILE dont le nom est passé en paramètre, en le copiant dans un répertoire temporaire sous le même nom. Dans un premier temps, on récupère le nom et le locator du BFILE au moyen d’une requête SQL du type SELECT et aux méthodes getBFILE() et getString(). private void recupererUnBfile(String name){ try{ Statement stmt=conn.createStatement(); ResultSet results=stmt.executeQuery("SELECT Photo,Nom FROM PHOTO WHERE Nom='"+name+"'"); //on prend le locator du bfile if(results.next()){ BFILE bfileloc=((OracleResultSet)results).getBFILE(1); String n=results.getString(2); Puis, on ouvre le fichier grâce à la méthode openFile(), et on ouvre un stream d’entrée sur ce dernier (InputStream) afin de permettre la lecture des données BFILEs, que l’on va écrire 16 dans un fichier (FileOutputStream) qui porte le nom du BFILE et qui va se trouver dans le répertoire C:\temp. Finalement, une fois l’écriture complète, on ferme les deux streams ainsi que le fichier. Il nous reste qu’à regarder dans le répertoire temporaire pour vérifier que le fichier a bien été créé. try{ bfileloc.openFile(); InputStream entree=blobloc.getBinaryStream(); //on ouvre un stream de sortie pour le blob FileOutputStream sortie=new FileOutputStream("C:\\temp\\"+n); byte[] buffer=new byte[10]; int nbread=0 ; //nombres de bytes lus while ((nbread=entree.read(buffer)) != -1) //lecture sortie.write(buffer,0,nbread); //ecriture sortie.flush(); sortie.close(); entree.close(); bfileloc.closeFile(); } 3.3 Servlet 3.3.1 Généralités Une fois le langage à utiliser pour la conception de présentations multimédias ainsi qu’un système de gestion de bases de données choisis, il faut maintenant s’intéresser à l’outil qui va permettre de récupérer les données multimédias de la base de données pour les afficher dans une présentation. Pour ce faire, j’ai choisi comme outil les servlets qui permettent de gérer des requêtes HTTP et de fournir au client une réponse dynamique. Les servlets sont des programmes java basés sur les packages javax.servlet.* et javax.servlet.http.* Un servlet peut générer dynamiquement une page HTML ou toute autre ressource web comme une image, un son, un texte … Cela permet de construire une page en fonction des souhaits du client, par exemple au moyen d’informations saisies dans un formulaire, en utilisant une base de données ou toute autre sorte de ressources locales ou distantes. Ils permettent donc de remédier à certains défauts des pages statiques, comme l’impossibilité de renvoyer une page personnalisée selon le visiteur ou encore l’impossibilité de créer une page dynamiquement selon les entrées d’une base de données. Un servlet peut être comparé à un applet mais s’exécutant du côté du serveur (comme les CGI, les scripts ASP ou PHP). Les servlets s’exécutent à l’aide d’un moteur de servlet qui établit le lien entre le serveur web et le servlet ; ces derniers ne sont chargés qu’une fois par le serveur, au démarrage du serveur ou lors de la première requête du client. Les servlets sont donc actifs en permanence, il n’y a pas besoin de créer un processus à chaque requête HTTP. Un servlet possède les principaux avantages suivants : • Il est indépendant du système d’exploitation. • Il est indépendant du serveur web utilisé (Tomcat, IIS, …). • Il est facile à développer, car en java ; possibilité de réutilisation car encapsulation de composants similaires possible, et possibilité d’utiliser toutes les API java. 17 3.3.2 Servlet et formulaire Les servlets rendent très simple la récupération de données envoyées par un formulaire HTML, et l’envoi d’informations sur le navigateur client en fonction de ces données reçues. Pour utiliser un formulaire avec un servlet, il suffit de mettre le nom du servlet qui réceptionnera les informations comme valeur de l’attribut action de la balise <form> et de spécifier la méthode HTTP à utiliser au moyen de l’attribut method. Dans l’exemple cidessous, le formulaire sera traité par un servlet nommé req et envoyé au moyen de la méthode GET. <form action="req" method=GET> Requete SQL: <input type=text size=80 name=donnee> <br> <input type=submit> </form> Deux méthodes permettent de définir sous quelle forme seront envoyées les données d’un formulaire : • Premièrement, la méthode GET qui permet d’envoyer les éléments du formulaire au moyen de l’URL du script, en ajoutant l’ensemble des paires nom/valeur à l’URL du script, séparé de celui-ci par un point d’interrogation, ce qui donne une URL du type: http://localhost :8080/examples/req ?donnee=blablabla • La méthode POST est une alternative à la méthode GET, elle code les informations de la même manière que la méthode GET mais envoie les données dans le corps de la requête. 3.3.3 Structure d’un servlet Maintenant, intéressons-nous à la structure du servlet permettant de traiter un formulaire. Vous avez pu lire qu’un servlet n’est chargé qu’une fois par le serveur, au démarrage du serveur ou lors de la première requête du client ; en fait, c’est la méthode init() qui est invoquée à chaque instantiation du servlet. De même, la méthode destroy() est appelée lors du déchargement du servlet. Ainsi, si notre servlet doit effectuer toute sorte de manipulations sur une base de données, on écrira le code de la connexion dans la méthode init(), ce qui permettra d’établir la connexion à la base de donnée au démarrage du serveur, et non à chaque requête d’un utilisateur. La structure de base du servlet java traitant un formulaire, avec accès à une base de données, est la suivante : Import java.io.* ; Import javax.servlet.* ; Import javax.servlet.http.* ; Public class req extends HttpServlet { public void init(ServletConfig config) throws ServletException { //connexion a la base de donnée } public void destroy() { //fermeture de la connexion 18 } public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //analyse de la requête (request) //lecture des données de formulaire HTML //production de la réponse (response) //envoi de la réponse au navigateur } } L’objet HTTPServletRequest encapsule la requête du client ; il contient l’ensemble des paramètres (champs de formulaire) passés au servlet. L’objet HTTPServletResponse permet quant à lui de renvoyer une réponse au client. La requête est traitée au moyen d’une des deux méthodes doGet() et doPost(), selon la méthode utilisée pour l’envoi du formulaire (GET et POST). 3.3.4 Exemple d’utilisation de servlet L’utilisation de servlets peut se résumer dans l’exemple suivant: Requête HTTP (par formulaire) Serveur web Requête SQL servlet Navigateur client réponse Moteur de servlets (Tomcat) réponse Base de données (Oracle) Dans un premier temps, l’utilisateur rempli un formulaire dans son navigateur web, et l’envoie. Le servlet, tournant sur un serveur web grâce à un moteur de servlets, récupère les données du formulaire et envoie une requête SQL à la base de donnée en fonction des informations remplies par l’utilisateur. La base de données exécute la requête puis donne la réponse au servlet, qui se charge de la retourner au client. 3.4 Lazy 3.4.1 Généralités Le dernier outil utilisé est le langage Lazy (développé par le groupe de recherche ISI du Centre Universitaire d’Informatique de l’Université de Genève) qui permet la publication de bases de données sur le web ; en d’autres termes, de présenter le contenu de bases de données sous forme d’hyperdocuments. Lazy est un langage déclaratif qui offre la possibilité de créer plusieurs vues différentes de données similaires, selon le point de vue de l’utilisateur, ce qui permet de personnaliser les documents hypertextes. Par exemple, des mêmes données pourront se trouver sous forme d’un tableau dans une page HTML et sous 19 forme d’une liste dans une autre page selon les besoins et l’usage que vont en faire les différents groupes d’utilisateurs. 3.4.2 Fonctionnement Chaque page web est une instance d’un nœud Lazy ; une vue hypertextuelle est un ensemble d’instances de nœud (et des liens qui existent entre ces instances). Un nœud est produit à partir d’une ou de plusieurs tables de la base de données, et se compose d’éléments qui vont former le contenu du nœud, ainsi que de liens vers d’autres nœuds. Les nœuds sont écrits en Lazy, et les instances de nœuds (les pages web) sont générées dynamiquement grâce à un serveur de nœud qui prend comme entrée une forme compilée de chacun des nœuds. Ainsi, le système Lazy est composé de : • Un langage déclaratif pour définir le contenu de chaque nœud et les liens que le nœud peut avoir avec d’autres noeuds. L’utilisateur va donc créer un nœud portant sur un ou plusieurs attributs d’une (ou de plusieurs) table(s) de la base de données (il faut donc préalablement connaître le schéma des tables de la base de données), en respectant la sémantique du langage Lazy et en donnant l’extension .lz (ou .lazy) à son fichier. • Un compilateur pour traduire les nœuds en interrogation de la base de données. Il faut donc compiler le nœud en lançant la commande java lc nom_du_noeud ; là, le compilateur va produire une requête SQL du type SELECT … FROM ... WHERE ... qu'il va mettre dans la table nodes (qui se trouve dans la base de données) avec pour nom le nom du noeud. • Un serveur de nœuds qui va récupèrer la requête (produite par le compilateur) dans la table nodes et va l’exécuter pour produire un document XML, HTML, SMIL ... selon les tags insérés dans le nœud lors de sa conception. 3.4.3 Création de nœuds Comme je l’ai déjà mentionné ci-dessus, un nœud permet de décrire comment sera générée une page web à partir de données stockées dans la base de données. Ainsi, à l’intérieur de chaque nœud il faut spécifier : - La table(s) sur laquelle porte le noeud Les critères de sélection et d’ordonencement des données Les éléments qui forment le contenu du nœud Les liens éventuels vers d’autres noeuds A noter que le nœud doit être créer dans un fichier source Lazy, qui est un simple fichier texte muni de l’extension .lz ou .lazy. La définition d’un nœud prend la forme suivante : define Node name [paramètres…] Elements … From table_name Selected by expression 20 Order by expression end Un élément peut être un string, un nombre, un attribut ou encore une expression arithmétique. Les éléments peuvent être des tags d’un langage de balisage (comme HTML ou SMIL), et ils prennent la syntaxe suivante : <title> (Petit exemple) équivaut à la notation HTML <title> Petit exemple </title> Tous les éléments spécifiés entre accolades {} sont répétés pour chaque tuple de la table qui satisfait aux exigences du selected by. Les éléments placés avant et après les accolades {} ne sont, quant à eux, générés qu’une seule fois. define node SMIL_image <smil> ( <head>( <meta name="title" content="Petit Exemple fait avec SMIL">(), <layout> ( <region id="image1" title="image1" top="0" left="0">() ) ), <body> ( <seq>( {<img region="image1" src=nom dur="5s">()} ) ) ) from Multimedia selected by type="image/jpeg" order by no_blob end L’exemple de nœud précédent, une fois compilé, puis exécuté par le serveur de nœuds, produira un document SMIL contenant toutes les images de la base de données qui sont du type image/jpeg et qui se trouvent dans la table Multimedia. L’attribut src de la balise <img> prendra la valeur de l’attribut nom de la table Multimedia pour chacune des images. Ainsi, si les éléments de la table Multimedia et de type image/jpeg ont pour nom : a.jpg, b.jpg, c.jpg, le résultat ressemblera à ceci : <smil> <head> <meta name="title" content="Petit Exemple fait avec SMIL"/> <layout> <region id="image1" title="image1" top="0" left="0"/> </layout> </head> <body> <seq> <img src="a.jpg" dur="5s"/> <img src="b.jpg" dur="5s"/> <img src="c.jpg" dur="5s"/> </seq> </body> </smil> La définition d’un nœud peut prendre un certain nombre de paramètres. L’exemple de nœud suivant prend un paramètre a qui va permettre de définir quelles images afficher. Ainsi, 21 seules les images ayant un identificateur supérieur au paramètre a (qui doit donc être de type numérique) vont être affichées : define node test[a] <p> ("Liste des images à partir de",a) {…} … from multimedia selected by no_blob>=a end On peut également spécifier qu’un élément est l’origine d’un autre nœud en utilisant la notation href, et même que le contenu d’un autre nœud est inclus dans le nœud que l’on définit, à l’endroit indiqué par la notation include. Ainsi, le nœud suivant possède un lien vers le nœud SMIL_image et contient le contenu du nœud test : define node essai[a] href SMIL_image("clickez ici pour les images"), include test[a] {…} … from multimedia selected by no_blob>=a end 4. Solution Une fois les différents outils trouvés, compris et appris, je peux maintenant m’attaquer à l’objectif final du travail qui est de pouvoir présenter le contenu d’une base de données multimédia sous la forme de documents SMIL générés à partir des images, photos, sons, textes, et autres vidéos stockés dans la base de données Oracle, aux moyen de nœuds Lazy. 4.1 Choix du domaine La première étape du travail a été celle du choix d’un domaine pour ma présentation. J’ai tout naturellement choisi comme sujet le hockey sur gazon, sport que je pratique depuis plus d’une dizaine d’années ; il se joue avec une canne et une balle, et oppose deux équipes de onze joueurs. Il m’a donc fallu dans un premier temps rechercher des données multimédias concernant ce sport. Cela n’a pas été une mince affaire car ce loisir, bien qu’il soit un des plus vieux sports olympiques, est encore très peu connu, et j’ai mis un certain temps à trouver des vidéos, photos et autres images sur le web. Une fois le domaine choisi, il m’a fallu le modéliser. 22 4.2 Modélisation du domaine J’ai défini un modèle du domaine très vaste (cf. page suivante), dont certaines relations ne seront pas utilisées lors de l’élaboration de l’exemple de présentation multimédia. Je suis parti de l’idée que tout joueur fait partie d’une (ou de plusieurs) équipe(s), qu’il possède son propre matériel (cannes, chaussures, …) et qu’il participe à un certain nombre d’entraînements durant la semaine ; chaque entraînement étant composé de diverses phases de jeu. Chaque équipe est inscrite à un championnat, qui est régi par différentes règles, et va donc jouer un certain nombre de matchs. Les photos peuvent représenter un ou plusieurs joueurs, une ou plusieurs équipes, ainsi que du matériel. Les vidéos quant à elles ne concernent que des règles ou des phases de jeu. Enfin, un son peut correspondre au commentaire d’un match. Il est bon de noter que les équipes peuvent être des équipes nationales (hommes ou femmes) participant à des championnats du monde ou à des Jeux Olympiques, tout comme des équipes amateurs participant à un championnat régional dans leur pays. J’en suis donc arrivé à la conception du modèle relationnel suivant. 23 4.2.1 Modèle relationnel Application_règles Règles Matchs Championnat Vidéo Image Son Inscription Matériel Phases_de_jeu Affectation Equipe Entrainement Possède Est_conposé Participe Joueur Fait_partie 4.3 Liste des relations et création des différentes tables La liste des relations découlant du modèle relationnel est la suivante : REGLE CHAMPIONNAT APPLICATION_REGLE EQUIPE INSCRIPTION MATCH SON JOUEUR FAIT_PARTIE IMAGE MATERIEL POSSEDE ENTRAINEMENT PHASE_DE_JEU EST_COMPOSE VIDEO AFFECTATION PARTICIPE (NoRegle // Nom, Description, DateRegle) (NoChampionnat // Categorie, Annee, Lieu) (NoChampionnat, NoRegle //) (NoEquipe // Nom, Adresse, Pays, NoTel, Categorie) (NoChampionnat, NoEquipe //) (NoMatch // Lieu, DateMatch, Heure, NoEquipe1, NoEquipe2) (NoSon // Nom, Description, Donnee, Type, NoMatch) (NoJoueur // Nom, Prenom, Adresse, Pays, NoTel) (NoJoueur, NoEquipe //) (NoImage // Nom, Description, Donnee, Type, NoMatch) (NoMateriel // Nom, TypeMateriel, Description) (NoJoueur, NoMateriel //) (NoEntrainement // JourSemaine, HeureDebut, HeureFin, DateEntr, Lieu) (NoPhase // Nom, Description) (NoEntrainement, NoPhase //) (NoVideo // Nom, Description, Donnee, Type, NoRegle, NoPhase) ( NoAffectation // NoImage, TypeImage, NoEquipe, NoJoueur, NoMateriel) (NoJoueur, NoEntrainement //) Les clés primaires définies dans les relations ci-dessus, ne sont pas définies au niveau de la création des tables [13]. En effet, je n’ai défini aucune contrainte ni règle d’intégrité, car elles ne sont pas nécessaires pour la conception de la présentation, et elles m’auraient fait perdre beaucoup de temps. 4.4 Insertion des données dans la base de données Une fois les différentes tables créées, j’ai inséré un certain nombre de valeurs (pour la plupart fictives) dans la base de donnée. Dans un premier temps, je me suis concentré sur les données textuelles, puis j’ai utilisé mon fichier java contenant la connexion à la base de données [7] pour insérer les données multimédias que j’avais trouvé. N’ayant pas trouvé de documents sonores sur le hockey sur gazon, j’ai décidé d’insérer quelques chansons. La plupart des photos trouvées concernant des matchs de hockey ayant eu lieu aux Jeux Olympiques de Sydney, les principales équipes insérées dans la bases sont des équipes nationales. Une fois les données textuelles et multimédias dans la base, j’ai rempli les attributs des différentes tables permettant de les associer entre elles. (Par exemple, l’image de nom sydney_all.gif est affectée à l’équipe dont le nom est Allemagne). Cette étape m’a pris un certain temps, car il fallait à chaque fois visualiser l’image (ou la vidéo) afin de savoir avec quelle(s) équipe(s), quel(s) joueur(s), quel(s) matériel(s), quelle règle ou encore quelle phase de jeu l’associer. De plus, n’ayant défini aucune règle d’intégrité, j’ai dû effectuer un certain nombre de vérifications permettant de m’assurer de l’intégrité des données. Toutes sortes de requêtes SQL peuvent maintenant être effectuées sur la base de données au moyen d’SQL*PLUS. Cependant, SQL*PLUS ne permet pas d’interroger directement des données 25 de type BLOB, et j’ai donc dû trouver un moyen permettant d’afficher ces données. J’en suis donc venu à la conception d’un servlet. 4.5 Conception d’un servlet pour la récupération des données L’étape suivante a été la conception d’un servlet traitant un formulaire rempli par l’utilisateur ; le formulaire va posséder un seul champ permettant à l’utilisateur d’effectuer une requête SQL sur les différentes données multimédias stockées dans la base de données. L’objectif du servlet est de récupérer les données de la base correspondant à la requête, et de les afficher dans le navigateur du client. Mais, comme je l’ai expliqué dans la partie sur les servlets (cf. point 3.3), un servlet nécessite un moteur de servlets et un serveur HTTP pour pouvoir s’exécuter. 4.5.1 Installation d’un serveur HTTP Il a donc fallu d’abord installer un serveur web, en l’occurrence Tomcat (à télécharger du site http://jakarta.apache.org), qui est un serveur HTTP et un moteur de servlets. J’ai choisi le produit d’Apache, car le serveur de nœuds utilisé par Lazy tourne également sur Tomcat. Pour l’installation sous Windows95 et 98, il ne faut pas oublier d’augmenter dans les propriétés des commandes MS-DOS la mémoire conventionnelle et de fixer l’environnement initial à 2048 ; sinon, un message d’erreur : « espace d’environnement initial insuffisant » apparaîtra lorsque l’on fixe les variables d’environnement. Ensuite, il faut définir des variables d’environnement ; la première doit pointer sur le répertoire où se trouve la JDK : set JAVA_HOME=H:\jdk1.2.2 et la seconde doit pointer sur le répertoire où l’on vient d’installer Tomcat : set TOMCAT_HOME=K:\memoire\tomcat. Ceci étant fait, il suffit d’exécuter bin/startup.bat pour lancer le serveur, et bin/shutdown.bat pour l’arrêter. On peut vérifier que le serveur a bien été installé avec http://localhost:8080, c’est la page d’accueil de notre serveur Tomcat. Une fois l’installation terminée, j’en suis venu à la conception du servlet. Trois fichiers ont été nécessaires à l’élaboration de ce dernier : un simple fichier HTML composé d’un formulaire à un champ dans lequel l’utilisateur pourra écrire sa requête, le servlet lui-même qui traite la requête envoyée par l’utilisateur et envoie la réponse sur le navigateur client, et enfin un fichier XML qui contient les valeurs par défaut des divers servlets déployés dans Tomcat. 4.5.2 Création du formulaire Tout d’abord, il faut créer un fichier HTML contenant le formulaire, et avec comme action pour ce formulaire, le nom du servlet qui va traiter la requête envoyée (le servlet s’appelle req). Le seul champ du formulaire (nommé donnee) va contenir une requête SQL faite par l’utilisateur, ce qui veut dire que ce dernier doit préalablement connaître les différentes tables présentes dans la base de données, ainsi que leurs attributs. <form action="req" method=GET> Requete SQL: <input type=text size=80 name=donnee> 26 <br> <input type=submit> </form> J’avais choisi, dans un premier temps, un formulaire à un champ qui prenait juste comme valeur le nom de la donnée multimédia à afficher, ce qui évitait à l’utilisateur de devoir formuler une requête SQL. Cependant, j’ai abandonné cette solution car elle ne permettait de faire des requêtes que sur une seule table de la base de données. J’ai donc opté pour la solution permettant de faire des requêtes sur toutes les tables présentes dans la base de données, mais nécessitant de formuler une requête SQL. Je vais expliquer quelles sont les requêtes possibles dans la partie suivante concernant l’élaboration du servlet (cf. point 4.5.3). L’inclusion de ce formulaire dans un fichier HTML nous donnera un document ressemblant à ceci : 4.5.3 Elaboration du servlet Une fois le formulaire fini, il m’a fallu concevoir le servlet permettant de traiter les données envoyées par la requête. Pour ce faire, il faut dans un premier temps importer les différents packages utiles à l’élaboration du servlet, ainsi que ceux nécessaires à la connexion à la base de données, et à la manipulation de ces données : 27 import import import import import javax.servlet.*; javax.servlet.http.*; java.sql.*; oracle.sql.*; oracle.jdbc.driver.*; Une fois de plus, pour que le compilateur java trouve ces différents packages, il est nécessaire de les définir dans le classpath : SET CLASSPATH= k:\memoire\tomcat\lib\servlet.jar;k:\memoire\oracle817\classes12.zip Ensuite, on déclare notre classe, et on construit la méthode init() qui va initialiser le servlet ; cette méthode contient le code relatif à la connexion JDBC à la base de données. Ainsi, la connexion à la base de donnée se fera au démarrage du serveur ou lors de la première requête du client, et non à chaque requête d’un utilisateur. public class req extends HttpServlet { <declaration des variables necessaires a la connexion> ServletContext scontext; public void init(ServletConfig config) throws ServletException { scontext = config.getServletContext(); <connexion a la base de donnee> } Comme le formulaire utilise la méthode d’envoi GET, une méthode doGet doit être définie dans le servlet afin de traiter les données envoyées. Cette méthode possède deux paramètres : request qui est la requête de l'utilisateur sous forme d'objet HttpServletRequest, et res qui est la réponse à fournir à l'utilisateur sous forme d'objet HttpServletResponse. Dans un premier temps, on ouvre un stream de sortie sur la réponse que l’on va afficher dans le navigateur du client, et on récupère les paramètres du champs du formulaire au moyen de la méthode getParameterNames(). Ensuite, pour chaque paramètre, on récupère son nom, puis sa valeur (c’est à dire le contenu du champ, qui est la requête SQL de l’utilisateur). Enfin, la méthodes recuperer est appelée avec pour attributs la requête SQL, le stream de sortie sur lequel écrire les données, et la réponse à fournir à l’utilisateur. public void doGet(HttpServletRequest request, HttpServletResponse res) throws IOException, ServletException { Enumeration e = request.getParameterNames(); OutputStream out = res.getOutputStream(); while (e.hasMoreElements()) { String name = (String)e.nextElement(); String value = request.getParameter(name); recuperer(value,out,res); } } La méthode recuperer va, dans un premier temps, exécuter la requête SQL sur la base de données. private void recuperer(String name, OutputStream out, HttpServletResponse res){ try{ Statement stmt=conn.createStatement(); ResultSet results=stmt.executeQuery(name); Ensuite, elle regarde quelle est la requête entrée par l’utilisateur afin de pouvoir traiter comme il se doit les données récupérées de la base. En effet, deux requêtes « standards » peuvent être formulées par un utilisateur: 28 1. SELECT donnee, type FROM … WHERE … 2. SELECT autre FROM … WHERE … A l’aide de ces deux types de requêtes, on peut normalement récupérer n’importe quelle donnée stockée dans la base, que ce soit une image, un son, une photo, une vidéo, des caractères, des chiffres… En effet, la première requête permet de récupérer une donnée multimédia quelconque, et la deuxième requête permet quant à elle de récupérer n’importe quelle autre donnée, sachant que toute donnée qui n’est pas multimédia (son, image, photo, vidéo) est forcément de type caractère ou numérique. Cependant, pour que cette manière de procéder fonctionne, j’ai dû nommer toutes les attributs de type BLOB des différentes tables de la base de données : donnee, et tous les attributs permettant de spécifier le type MIME de ces données BLOBs : type [13]. Si l’utilisateur veut effectuer une requête lui retournant une donnée de type multimédia, il devra donc faire un SELECT donnee, type et si il souhaite faire une requête sur tout autre(s) attribut(s) d’une table, il lui suffit de préciser les attributs désirés dans sa requête. Pour savoir quelle est le type de la requête envoyée par l’utilisateur, on regarde les caractères situés en neuvième et dixième positions de la requête : si le caractère située en neuvième position est un ‘o’ et celui situé en dixième position est un ‘n’, on est dans le cas d’un SELECT donnee, type FROM … WHERE … On doit donc récupérer un BLOB (la donnée multimédia) et un string (le type MIME de la donnée) ; puis on définit que le type MIME de la réponse HTTP envoyée au navigateur client correspond au type MIME de la donnée multimédia, ceci grâce à la méthode setContentType(). Finalement, on lit la donnée BLOB, et on l’écrit sur le stream de sortie. if(((name.charAt(8))=='o')&&((name.charAt(9))=='n')){ //on prend le locator du blob if(results.next()){ BLOB blobloc=((OracleResultSet)results).getBLOB(1); String n=results.getString(2); try{ res.setContentType(n); InputStream entree=blobloc.getBinaryStream(); int chunk=blobloc.getChunkSize() ; byte[] buffer=new byte[chunk]; int nbread=0 ; //nombres de bytes lus while ((nbread=entree.read(buffer)) != -1) out.write(buffer,0,nbread); //ecriture out.flush(); out.close(); entree.close(); } } } Si on est dans le cas d’un SELECT autre FROM … WHERE … on doit récupérer un ou plusieurs strings car on a affaire à des données de type caractère ou de type numérique (il est possible d’effectuer un getString() d’un attribut d’une table qui est de type number). On regarde tout d’abord combien de strings on doit récupérer, au moyen d’une boucle for et d’un compteur a. Ainsi, chaque fois que l’on trouve une virgule, avant d’avoir atteint la clause FROM, on rajoute une unité au compteur (la variable c permet de savoir si la clause FROM a déjà été atteinte). Par exemple, si l’utilisateur écrit une requête du type : SELECT nom, description from equipe where noequipe=’1’, la valeur de a sera deux. else{ int a=1,c=0; for(int i=0;i<name.length();i++){ 29 if((name.charAt(i)=='f')&&(name.charAt(i+1)=='r')&&(name.charAt (i+2)=='o')) c=1; if((name.charAt(i)==',')&&(c==0)) a++; } Puis on récupère le(s) résultat(s) de la requête, et on définit le type MIME de la réponse HTTP comme étant du texte. Finalement, on écrit la (les) donnée(s) sur le stream de sortie. if(results.next()){ String first=results.getString(1); if(a>=2) second=results.getString(2); if(a>=3) third=results.getString(3); … try{ res.setContentType("text/vnd.rn-realtext"); out.write(first.getBytes()); if(a>=2){ out.write(second.getBytes()); } if(a>=3){ out.write(third.getBytes()); } … 4.5.4 Modification du fichier web.xml La dernière étape a été la modification du fichier web.xml avec le rajout de ces quelques lignes dans ce fichier qui contient les valeurs des diverses applications déployées dans Tomcat, et qui permet de spécifier le nom et la classe du servlet. <servlet> <servlet-name> req </servlet-name> <servlet-class> req </servlet-class> </servlet> <servlet-mapping> <servlet-name> req </servlet-name> <url-pattern> /req </url-pattern> </servlet-mapping> 30 4.5.5 Vue d’ensemble Voici à quoi ressemble l’arborescence de mes fichiers, une fois ceux-ci créés et modifiés : + - tomcat +- webapps +- examples *- req.html +- WEB-INF *- web.xml +- classes *- req.java Pour tester le servlet, il suffit d’aller à l’URL : http://localhost:8080/examples/req.html 4.5.6 Exemple de requête Une fois arrivé sur la page contenant le formulaire, il ne nous reste plus qu’à tester le servlet en rentrant une requête SQL dans le champ du formulaire, du type : SELECT donnee,type FROM image WHERE nom='img1.gif' Si tout se passe bien, la photo correspondant à la requête apparaît dans le navigateur, avec pour URL : http://localhost:8080/examples/req?donnee=SELECT+donnee%2Ctype+FROM+multimedia+ WHERE+nom%3D%27img1.gif%27 Le fait d’utiliser la méthode d’envoi GET permet de connaître l’URL correspondant à une requête, au moyen du servlet, sur la base de données. On va donc pouvoir concevoir des présentations SMIL où les différentes données multimédias seront référencées au moyen de cet URL. 4.6 Choix d’un player Par la suite, j’en suis venu à concevoir un document SMIL simple à l’aide d’un éditeur de texte afin de tester le bon fonctionnement du servlet, mais surtout des différents players SMIL (cf. point 3.1.4). J’ai donc créé un document SMIL [11] qui joue différentes images en séquence, accompagnées d’une chanson et d’un texte descriptif pour chacune d’entre elle, et suivi d’une séquence vidéo. Cet exemple permet de tester tous les types de médias dans les différents players. Une fois la présentation créée, j’ai décidé de la tester dans les différents players afin de choisir lequel j’allais utiliser par la suite. Mais là, j’ai eu la mauvaise surprise de voir qu’aucun 31 player n’était capable de jouer mon exemple en intégralité ! ! ! Tout d’abord, RealPlayer8 qui supporte la version SMIL 1.0, ne permet pas de jouer des images de type jpeg en séquence. Ensuite, QuickTime, qui supporte également la version SMIL 1.0, mettait du temps à charger des images ne dépassant pas la taille de 10 Ko, et les images qui devaient s’afficher pendant cinq secondes ne s’affichaient donc même pas ! ! ! Enfin, GriNS jouait les images, mais pas le son ni la vidéo … Il semble que les développeurs de players sortent leur produit le plus vite possible sur le marché, sans se soucier des bugs résiduels, avec pour seul souci d’être le premier sur le marché dans un domaine qui bouge très rapidement. J’ai donc passé énormément de temps à essayer de contourner les problèmes de ces différents players, en vain … Ensuite, je me suis tourné vers la solution Internet Explorer qui « supporte SMIL 2.0 à partir de sa version 5.5» dit-on sur le site de Microsoft. J’ai donc voulu ouvrir mon document SMIL dans le navigateur, mais ce dernier l’ouvrait dans RealPlayer8 et non pas dans le navigateur lui-même ! J’ai alors effectué quelques recherches sur le web afin de comprendre comment utiliser SMIL avec Internet Explorer ; c’est là que j’ai trouvé que le produit de Microsoft ne supporte pas SMIL mais un langage dérivé (basé sur les spécifications de SMIL) nommé HTML+TIME ! ! ! Vu que c’était la dernière solution qu’il me restait, j’ai décidé de concevoir mon exemple en HTML+TIME afin de voir si tout marchait correctement. 4.6.1 HTML+TIME J’ai commencé par apprendre ce langage (approuvé par le W3C) qui permet d’étendre les fonctionnalités de SMIL aux navigateurs webs. En fait, HTML+TIME (nommé XHTML+SMIL à partir de la version 6 d’Explorer) définit un certain nombre d’améliorations apportées à HTML permettant d’ajouter une ligne temporelle, de l’interaction, ainsi qu’une synchronisation entre les divers médias présents dans une page web afin de créer des présentations dynamiques et interactives, toutes ces différentes caractéristiques étant basées sur les spécifications et la terminologie de SMIL. En fait, HTML+TIME poursuit les mêmes buts que SMIL, mais en voulant intégrer les différents balises SMIL dans un document HTML pour pouvoir visualiser la présentation dans un navigateur et non pas dans un player. Avec le développement de ce langage, Microsoft essaie de contrer l’invasion de l’industrie des players dans le domaine des navigateurs webs, en essayant de s’implanter sur leur marché ; cependant, ce langage n’a pas encore le succès escompté. 4.6.1.1 Structure d’un document HTML+TIME Trois composants de base se trouvent dans l’entête d’un document HTML+TIME. Premièrement, il faut déclarer le namespace du temps dans le tag <html>. <html xmlns:t ="urn:schemas-microsoft-com:time" > Ensuite, il faut spécifier un style pour le comportement du time2 et importer son comportement. Ce code doit figurer dans chaque entête de document HTML+TIME : <head> <style> .time { behavior: url(#default#TIME2); } </style> <?import namespace="t" implementation="#default#time2"> </head> 32 Maintenant, dans le corps du document, il est possible d’introduire des balises <par> et <seq>, ainsi que toutes sortes d’attributs (begin, dur, …) ressemblants fortement à ceux présents dans des documents SMIL. <body> <t:seq> <t:par> <img class="time" begin="0" dur="3" src="img1.jpg"/> <div class="time" begin="0" dur="3">Pakistan-Allemagne</div> </t:par> </t:seq> </body> Ainsi, l’équivalent d’un document SMIL [12] est le fichier HTML+TIME [13]. On peut remarquer que ces deux exemples possèdent un certain nombre de ressemblances sans toutefois être complètement similaires. Cette solution d’utiliser HTML+TIME ne m’a pas vraiment convaincu car ce langage possède un certain nombre de défauts : il n’est, par exemple, reconnu que par les versions récentes d’Internet Explorer, les balises sont un peu plus complexes à utiliser que celles présentes en SMIL, et il est, à mon avis, loin de devenir un standard au même titre que son homologue. Le seul point positif réside dans le fait que des pages HTML existantes peuvent être améliorées (du point de vue de la présentation et de l’interactivité) en peu de temps au moyen de ce langage. Cette solution ne m’a donc pas entièrement satisfait, et je suis reparti à la recherche d’un player qui puisse jouer mon exemple de présentation SMIL sans aucun bug …Je me suis donc redirigé dans un premier temps vers QuickTime, en essayant de comprendre d’où provenait le problème du chargement extrêmement lent des données multimédias, sans toutefois trouver de réponse. Mais au moment où je commençais à baisser les bras, RealONE m’a tendu les siens ! ! ! 4.6.2 RealONE En surfant par hasard sur le web, j’ai découvert que RealNetworks sortait un nouveau player en septembre 2001 (faisant également navigateur web) nommé RealONE. Je l’ai donc téléchargé dès sa sortie, et j’ai testé mon exemple [11]. Là, ô miracle des technologies modernes, ma présentation se jouait sans aucun problème, ou presque. En effet, RealONE, comme RealPlayer, ne supporte pas très bien les images de type jpeg qui sont jouées en séquence. J’ai donc décidé de convertir toutes les photos présentent dans la base de données au format gif, puis j’ai testé à nouveau mon exemple : tout marchait à merveille ! ! ! De plus, contrairement aux autres players SMIL, RealONE supporte les spécifications de SMIL 2.0, et il est donc possible d’utiliser, entre autre, le module d’animation définit dans SMIL 2.0 permettant principalement d’animer les images et autres données multimédias présentes dans une présentation. 4.7 Installation de Lazy Une fois le player SMIL choisi, l’étape suivante a été d’installer Lazy (téléchargeable sur le site http://cui.unige.ch/isi/lazy) afin de pouvoir créer des documents SMIL dynamiquement, sur la base de nœuds. Tomcat étant déjà installé, il suffit d’installer le compilateur (Compiler.class et lc.class) et le serveur de nœud (ns.class), sans oublier de modifier le 33 fichier web.xml (comme dans le cas du point 4.5.4). Les trois classes ci-dessus doivent être insérées dans le même répertoire que le servlet créé précédemment (cf. point 4.5.5). De plus, il faut insérer dans la base de données les tables nodes (qui va contenir les valeurs des nœuds compilés) et naturals (qui contient les entiers de 0 à 9, et qui va servir pour les nœuds prenant des paramètres). Il faut également définir un fichier Lazy.properties dans le répertoire où seront créés les différents nœuds : il contient les ressources nécessaires pour le compilateur et le serveur de nœuds Lazy, à savoir l’URL de la base de donnée, le nom d’utilisateur, le mot de passe, le driver utilisé, et le nom du serveur de nœuds. 4.8 Conception de nœuds SMIL en Lazy 4.8.1 Modification du serveur de nœuds Pour pouvoir créer des présentations SMIL en Lazy, il faut tout d’abord modifier le serveur de nœud (ns.java). En effet, le serveur de nœuds produit par défaut une en-tête HTML, et définit le type MIME du nœud compilé comme étant de type HTML. J’ai dû modifier quelque peu le serveur de nœuds afin que ce dernier définisse le type MIME correctement, selon le nom que l’on donne à notre nœud. De ce fait, si le nom du nœud commence par SMIL_, le type MIME sera défini comme étant celui d’une application SMIL, sinon ce sera celui d’un document HTML. String a = request.getParameterValues("a")[0]; if(a.startsWith("SMIL_")) response.setContentType("application/smil"); else response.setContentType("text/html"); De plus, dans le cas d’un nœud SMIL, aucune en-tête ne doit être insérée dans le nœud compilé ; toutes les balises SMIL seront définies au niveau de la création du nœud. if(!a.startsWith("SMIL_")&&!a.startsWith("HTML_")){ out.println("<html>"); out.println("<head>"); out.println("<title>Node: " + a +"[" + ul + "]" + "</title>"); out.println("</head>"); out.println("<body>"); } J’ai également modifié le serveur de nœuds afin qu’il permette la création de documents HTML+TIME. De la même manière, tous les nœuds dont le nom commence par HTML_, auront une en-tête qui leur est propre (cf. point 4.6.1.1). if(a.startsWith("HTML_")){ out.println("<html xmlns:t =\"urn:schemas-microsoft-com:time\">"); out.println("<head>"); out.println("<style> .time { behavior: url(#default#TIME2); }"); out.println("</style>"); out.println("<title>Node: " + a +"[" + ul + "]" + "</title>"); out.println("<?import namespace=\"t\" implementation=\"#default#time2\">"); out.println("</head>"); out.println("<body>"); } 34 De même, des balises de fin de document sont insérées dans le cas de nœuds « normaux », balises qui ne sont pas insérées si le nom du nœud commence par SMIL_. 4.8.2 Conception de nœuds SMIL Une fois le serveur de nœud modifié, j’ai pu concevoir quelques nœuds SMIL en Lazy, afin de vérifier le bon fonctionnement du tout, et avant de m’attaquer à la présentation finale. J’ai, par exemple, créé un nœud [15] qui joue une série d’images les unes à la suite des autres (une sorte de diaporama). Une fois le nœud conçu, il suffit de le compiler, puis d’aller sur la page où se trouve l’ensemble de mes nœuds (http://localhost :8080/examples/ns?a=meta), et enfin de cliquer sur le nom du nœud (le nœud doit avoir un nom commençant par SMIL_ cf. point 4.8.1) ; si tout se passe bien, RealONE va s’ouvrir et jouer ma présentation. De la même manière, j’ai défini quelques autres nœuds afin de voir si les différents médias – que se soient des images, du son, du texte, ou encore des vidéos – se jouaient correctement. Les médias sont référencés dans un nœud Lazy au moyen de l’URL utilisé par la méthode d’envoi GET correspondant à une requête à l’aide du servlet sur la base de donnée (cf. point 4.5.6). Toute référence à un média se fera de la manière suivante : on définit, dans un premier temps, la balise correspondant au type du média que l’on souhaite afficher ainsi que la region dans laquelle il s’affichera, puis on donne comme source pour ce média l’URL produit par la méthode GET. Dans l’exemple suivant, tous les tuples de la table choisie, et correspondants aux critères de sélection, seront affichés sous la forme d’image. {<img region="image" src="http://localhost:8080/examples/req?donnee=SELECT+donnee%2Ctype+FROM+mu ltimedia+WHERE+nom%3D%27",nom,"%27" dur="5s">()} 4.9 Présentation finale Finalement, je suis arrivé à l’ultime étape de mon travail, avec la création d’un exemple de présentation dynamique sur le hockey sur gazon. J’ai conçu un exemple assez simple, mais permettant de montrer les possibilités offertes par une base de données multimédia utilisée à l’aide des langages SMIL et Lazy. L’utilisateur va pouvoir naviguer dans l’information, interagir avec cette dernière en cliquant sur les liens qui l’intéresse car les différents nœuds possèdent des références les uns aux autres ; il y a donc plusieurs moyens de voir l’information. Je n’ai produit que cinq nœuds en me basant sur une partie de la modélisation du domaine (cf. point 4.2.1) ; nœuds qui me paraissaient les plus pertinents d’après le modèle, et surtout d’après les données trouvées sur le web. 4.9.1 Détails des nœuds créés Le premier nœud [16] permet d’afficher en musique toutes les photos concernant l’équipe choisie par l’utilisateur : il doit rentrer comme paramètre le nom de l’équipe. Ce nœud possède un lien vers celui contenant les règle du hockey sur gazon [19] , un autre vers la 35 liste des équipes [17], et enfin un dernier vers le détail des matchs que l’équipe doit jouer [18]. De plus, un nœud affichant les matchs à jouer [20] est inclus dans ce nœud. Le second nœud [19] permet d’afficher les règles du hockey sur gazon, et chacune des règles possède un lien vers une vidéo explicative ; ce nœud possède également un lien vers la liste des équipes. Le troisième nœud [17], quant à lui, permet d’afficher la liste des équipes et de choisir celle qui nous intéresse ; il possède un lien vers le site de la fédération internationale de hockey. Enfin, le dernier nœud [18] permet d’obtenir le détail des matchs concernant une équipe. 4.9.2 Problèmes rencontrés J’ai rencontré un certain nombre de problèmes lors de l’élaboration de ma présentation : • Premièrement, il m’a fallu augmenter la taille de certains attributs de la tables nodes. En effet, les attributs pre et items sont définis à la base comme étant de type Varchar2(2000). Or, cette taille n’est pas suffisante pour produire des documents SMIL complexes, j’ai donc dû l’augmenter (Varchar2(4000)). • Ensuite, SMIL étant basé sur XML, et XML ne supportant pas le caractère &, il m’a donc fallu remplacer tous les caractères & présents dans les différents nœuds Lazy par & ; (Le caractère & est essentiellement présent lorsque l’on référence un nœud dans un autre nœud.) • De plus, il n’est pas possible d’introduire du texte « en dur » dans une présentation SMIL ; le texte s’affichant dans la présentation doit se trouver dans la base de données (ou dans un fichier). J’ai donc dû créer une table legende contenant certains textes apparaissant dans la présentation. 5. Conclusion Le multimédia est un domaine qui bouge énormément, et très rapidement ; j’en veux pour preuve la « découverte » de RealONE, un jour après sa sortie. Ainsi, beaucoup de nouveautés apparaissent sans cesse que ce soit dans le domaine des players ou même dans le domaine des langages de présentation de données multimédias. En me basant sur les dernières spécifications, j’ai dû effectuer beaucoup de recherche car, du fait de cette nouveauté, j’ai touché à des domaines qui étaient encore très peu explorés et, où peu d’informations et d’exemples les concernants étaient disponibles. Ce travail a permis de mettre en pratique et d'approfondir mes connaissances dans trois domaines de l'informatique les plus dynamiques actuellement : - les bases de données - le web - le multimédia Grâce aux nouveaux types définis dans Oracle (LOBS) et à des langages bien adaptés pour ce genre d'applications (java, SMIL et Lazy), il a été possible de concevoir rapidement des documents multimédias. Mais la plus grosse difficulté est venue des players : sans la découverte tardive de RealONE, le seul capable d'afficher correctement tout type de 36 documents SMIL, il aurait été impossible de démontrer le bon fonctionnement de mon application. Je garde le mot de la fin pour remercier ceux qui m’ont aidé et/ou supporté lors de l’élaboration de ce travail : à savoir ma famille et ma copine. Je tiens tout particulièrement à remercier le professeur Gilles Falquet pour son aide et ses conseils avisés. 6. Bibliographie [1] A. Michard, « XML, langage et applications », Eyrolles, 1999. [2] R. Plew et K. Stephens, « SQL », CampusPress, 2000. [3] V.S. Subrahmanian, « Principles of Multimedia Database Systems », Morgan Kaufmann, 1998. [4] M. Vazirgiannis, « Interactive Multimedia Documents », Springer, 1999. [5] S.J. Gibbs et D.C. Tsichritzis, « Multimedia Programming », Addison-Wesley, 1995. [6] S. Khoshafian et A.B. Baker, « Multimedia and Imaging Databases, Morgan Kaufmann, 1996. les LOBs et autres types de données: Oracle8 Server Application Developer’s Guide, http://hojohn.photo.net/ora8doc/DOC/server803/A54642_01/ch_lob.htm Oracle/SQL Tutorial, Michael Oertz, http://sirius.cs.ucdavis.edu/teaching/sqltutorial Oracle Data Type, http://www.idera.com/support/documentation Forum de DBA, http://www.dbasupport.com/forums JDBC : Connexion JDBC à la base de données, http://www.commentcamarche.net/jdbc/jdbcconnect.php3 Exécution de requêtes SQL sur la base de données, http:// www.commentcamarche.net/jdbc/jdbcexec.php3 JDBC, Roger Whitney, http://www.eli.sdsu.edu/courses/fall00/cs580/notes/jdbc/jdbc.html TOMCAT : Tomcat User’s Guide, http://jakarta.apache.org/tomcat/tomcat-3.2-doc/uguide/tomcat_ug.html 37 SMIL et HTML+TIME: Synchronized Multimedia Integration Language (SMIL 2.0), August 2001, http://www.w3.org/TR/smil20/ Timed Interactive Multimedia Extensions for HTML, http://www.w3.org/TR/NOTE-HTMLplusTIME SMIL – présentation intéractive, N. Mérat et S. Nastasi, mai 2000, http://cui.unige.ch/~nastasi7/smil/index.html Quicktime and SMIL, http://www.apple.com/quicktime/authoring/qtsmil2.html SMIL tutorials, http://streamingmediaworld.com/smil/tutor Is HTML+TIME Out-of-Sync With SMIL ?, Lisa Rein, 1998, http://www.xml.com/pub/a/98/10/htmltime.html LAZY : Lazy Home Page, http://cui.unige.ch/isi/lazy 7. Annexes [7] ConJDBC.java [8] req.html [9] req.java [10] web.xml [11] player.smil [12] hockey.smil [13] hockey.html [14] create_tables.sql [15] SMIL_image.lz [16] SMIL_equipe.lz [17] SMIL_liste.lz [18] SMIL_match.lz [19] SMIL_regle.lz [20] SMIL_mixmatch.lz 38