Université de Sherbrooke, Département d informatique IFT287 : Exploitation de BD relationnelles et OO, Examen final Professeur : Marc Frappier, Vendredi 15 décembre 2006, 9h00 à 12h00 Documentation permise. La correction est, entre autres, basée sur le fait que chacune de vos réponses soit claire, c est-à-dire lisible et compréhensible pour le lecteur; précise, c est-à-dire exacte et sans erreur; concise, c est-à-dire qu il n y ait pas d élément superflu; complète, c est-àdire que tous les éléments requis sont présents. Pondération : 1 2 3 4 5 6 total 20 20 15 15 20 10 100 Nom : Prénom : Signature : Matricule : 1) (20 pts) a) (15 pts) Donnez le diagramme de classe UML permettant de modéliser avec une base de données objets le système décrit ci-après. Attention : ne donnez pas les gestionnaires de transaction, de collection et de connexion; donnez seulement les classes contenant des données persistantes; modélisez seulement les attributs mentionnés; ne donnez pas les méthodes; modélisez tous les attributs apparaissant dans la description; respectez la structure imposée par la description. Le système doit gérer la vente aux enchères d'articles divers sur le web. Les articles soumis ont un numéro d'identification, une description, un vendeur, un prix minimal et une date limite pour l'acceptation des offres d'achat. Les acheteurs soumettent leur offre en mentionnant le prix offert pour un article donné. Pour être acceptée, l'offre doit être soumise avant la date limite associée à l'article et supérieure ou égale au prix minimum fixé par le vendeur. Les acheteurs et les vendeurs doivent s'inscrire au système, afin de pouvoir participer, en mentionnant les informations suivantes : nom, adresse, numéro de carte de crédit. Lorsque la date limite pour la vente d'un article est atteinte, l'offre la plus élevée est retenue. Une transaction de paiement par carte de crédit est alors effectuée. Cette transaction comporte les informations suivantes : l'acheteur, l'article acheté, la date de la transaction. Si l'acheteur n'a pas reçu l'article dans les 15 jours suivants la date de transaction, l'acheteur est remboursé en créditant sa carte de crédit. Les transactions de remboursement doivent être aussi conservées dans le système. 1/10
Espace réponse de la question 1) a) articlesavendre 0..* Article noarticle prixminimum datelimite article 1 offreretenue 0..1 offresachat * prix date Offre offresretenues 0..* offresachat * Membre nomembre adresse telephone nocartecredit membre 1 vendeur 0..* paiment 0..1 remboursement 0..1 Transaction date type b) (5 pts) Servlet : Indiquez quelle partie (Context, Session ou Request) vous utiliseriez pour sauvegarder les aspects suivants. 1. Un ensemble d'instances de gestionnaires de transactions à partager entre plusieurs utilisateurs. _Contexte 2. Le user id entré par un utilisateur lors de sa connexion au système. _Session 3. Une liste d'éléments calculée par un servlet pour répondre à une requête d'un utilisateur. Cette liste ne sera pas utilisée dans les autres requêtes suivantes. Cette liste est affichée via une page JSP. _Request 4. Une liste d'éléments calculée pour répondre à une requête d'un utilisateur; cette liste sera aussi utilisée dans les autres requêtes que l'utilisateur pourra effectuer par la suite. _Session 2/10
2) (20 pts) Considérez le diagramme de classe de la figure 1 ci-dessous. a) (7 pts) Donnez les déclarations des classes persistantes correspondant à ce diagramme. Donnez seulement les attributs; ne donnez pas les méthodes pour l'instant. D'un TupleB, on désire avoir un accès direct et rapide (temps constant k ou log(n)) à une instance de TupleC via l'attribut e. TupleA -a : int -r3 1..* -r4 1..1 TupleB -b : int -c : String e : int -r5 1 -r6 * -d : int TupleC 1..1 -r1 -r2 0..1 Figure 1 public class TupleA private int a; private TupleB r4, r2; public class TupleB private int b; private String c; private Set r3; private TupleA r1; private Map r6; public class TupleC private int e; private int d; private TupleB r5; b) (3 pts) Codez le constructeur de la classe TupleB. public TupleB(int b, String c, TupleA r1, TupleA r3 ) this.b = b; this.c = c; this.r1 = r1; this.r3 = new OSHashSet(); this.r3.add(r3); this.r6 = new OSHashMap(); c) (10 pts) Codez avec ObjectStore la transaction t1 dont la déclaration est: public void t1(int b, int emin, int emax) throws Exception et qui effectue le traitement suivant. On suppose que le paramètre b permet d'identifier un TupleB de manière unique (c'est une clé). La transaction t1 doit supprimer tous les TupleC reliés au TupleB et identifiés par le paramètre e et satisfaisant emin <= e <= Emax. On suppose que la méthode t1 fait partie d'un gestionnaire de transactions et qu'elle a accès aux gestionnaires de collection appropriés. Ne donnez pas le code des gestionnaires de collection ni celui des classes TupleX. Appelez simplement les méthodes appropriées en supposant qu'elles sont définies. Donnez votre réponse à la page suivante. 3/10
public void t1(int b, int emin, int emax) throws Exception public void t1(int b, int emin, int emax) throws Exception Transaction tr = Transaction.begin(ObjectStore.UPDATE); try /* Vérifie si le TupleB existe */ TupleB tb = collb.get(b); if (tb == null) throw new Exception("TupleB de cle " + b + "n'existe pas."); /* Suppresion des TupleC */ Iterator it = tb.getr6().values().iterator(); while (it.hasnext()) TupleC tc = (TupleC) it.next(); if (tc.gete() >= emin && tc.gete() <= emax) it.remove(); tr.commit(objectstore.retain_hollow); catch (Exception e) tr.abort(objectstore.retain_hollow); throw e; 4/10
3) (15 pts) Complétez la page JSP ci-dessous qui utilise un DOM pour produire la page HTML de la figure 2 (page suivante) à partir d'un fichier XML qui satisfaisait la DTD de la figure 2.... debut du JSP... <BODY> DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setvalidating(true); factory.setignoringelementcontentwhitespace(true); factory.setignoringcomments(true); DocumentBuilder builder = factory.newdocumentbuilder(); Document document = builder.parse(new File("cours.xml")); Node n = document.getfirstchild(); while (n!= null && n.getnodetype()!= Node.ELEMENT_NODE) n = n.getnextsibling(); n = n.getfirstchild(); // première auto <H1>Liste des autos </H1> <ol> while (n!= null) Node essenceouelectrique = n.getfirstchild(); <li> Modèle : = n.getattributes().getnameditem("modele").getnodevalue(), Consommation : = n.getattributes().getnameditem("consommation").getnodevalue() = n.getattributes().getnameditem("unite").getnodevalue(), if (essenceouelectrique.getnodename().equals("essence")) Nombre de cylindres = = essenceouelectrique.getattributes().getnameditem("nbcylindre").getnodevalue() else Caractéristiques = = essenceouelectrique.getfirstchild().getnodevalue(). </li> n = n.getnextsibling(); </ol> </BODY> 5/10
DTD <?xml version='1.0' encoding='iso-8859-1'?> <!ELEMENT listeauto (auto)*> <!ELEMENT auto (essence electrique)> <!ATTLIST auto modele CDATA #REQUIRED consommation CDATA #REQUIRED unite CDATA #REQUIRED > <!ELEMENT essence EMPTY> <!ATTLIST essence nbcylindre CDATA #REQUIRED > <!ELEMENT electrique (#PCDATA)> Fichier XML <?xml version="1.0" encoding="iso-8859-1" standalone="no"?> <!DOCTYPE listeauto SYSTEM "auto.dtd"> <listeauto> <auto modele="prius" consommation="4" unite="l/100km"> <electrique>moteur électrique de 57 KW/h</electrique> </auto> <auto modele="hummer" consommation="50" unite="l/100km"> <essence nbcylindre="12"/> </auto> <auto modele="civic" consommation="3.3" unite="l/100km"> <electrique>moteur électrique de 10 KW/h IMA</electrique> </auto> </listeauto> Figure 2 6/10
4) (15 pts) Utilisez un SAXParser pour déterminer l'automobile ayant la consommation maximale pour un fichier XML satisfaisant la DTD de la figure 2. Pour le fichier xml de cette figure, le programme doit produire la sortie suivante. Auto ayant la consommation maximale Modèle : hummer Consommation : 50 L/100km Naturellement, on suppose que toutes les consommations sont exprimées avec la même unité. Vous ne codez que les parties suivantes : déclaration des variables globales; méthodes suivantes (si nécessaire) : startelement, endelement, characters. Déclaration de variables globales private static float max = 0; private static String modele, unite; Déclaration des méthodes nécessaires public void startelement(string n, String l, String qname, Attributes attrs) throws SAXException if (qname.equals("auto")) float consommation = Float.parseFloat(attrs.getValue("consommation")); if (consommation > max) max = consommation; modele = attrs.getvalue("modele"); unite = attrs.getvalue("unite"); public void endelement(string n, String l, String qname) throws SAXException if (qname.equals("listeauto")) System.out.println("Auto ayant la consommation maximale"); System.out.println("Modèle : " + modele); System.out.println("Consommation : " + max + " " + unite); public void characters(char buf[], int offset, int len) 7/10
5) (20 pts) Servlet a) (17 pts) La page web ci-dessous affiche un Map qui est conservé dans l'attribut map du contexte de l'application. Le contenu de ce Map est accessible à tous les utilisateurs. Le bouton «insérer» ajoute une nouvelle entrée au Map; le bouton «supprimer» supprime l'entrée sélectionnée. Code HTML de la page <FORM ACTION="Q5" METHOD="POST"> <table> <tr> <td>sélection</td> <td>clé</td> <td>valeur</td> </tr> Map m = (Map) getservletcontext().getattribute("map"); Iterator it = m.keyset().iterator(); while (it.hasnext()) Integer cle = (Integer) it.next(); Integer valeur = (Integer) m.get(cle); <tr> <td><input TYPE="RADIO" NAME="item" VALUE="=cle.intValue()"></td> <td>= cle.intvalue()</td> <td>= valeur.intvalue()</td> </tr> </table><br> <INPUT TYPE="SUBMIT" NAME="supprimer" VALUE="supprimer"><BR><BR> cle : <INPUT TYPE="TEXT" NAME="cle"> valeur : <INPUT TYPE="TEXT" NAME="valeur"> <BR><BR><INPUT TYPE="SUBMIT" NAME="inserer" VALUE="insérer"> </FORM> Codez la méthode dopost qui traite ce formulaire. Notez bien que si deux thread modifient un Map en parallèle, le Map peut être corrompu, car les implémentations de Map ne sont pas synchronisées par défaut. Si l'appel termine avec succès, on réaffiche la liste des entrées du Map. Complétez le code de la méthode dopost (page suivante). Vous pouvez utiliser la méthode convertir ci-dessous qui convertit une String en un Integer. public static Integer convertir(string v) try return new Integer(v); catch (Exception e) return null; 8/10
public class Q5 extends HttpServlet public void dopost(httpservletrequest request, HttpServletResponse response) throws ServletException, IOException try Map m = (Map) getservletcontext().getattribute("map"); Integer cle; Integer valeur; synchronized (m) if (request.getparameter("inserer")!= null) cle = convertir(request.getparameter("cle")); if (cle == null) throw new Exception("Champs cle incorrect"); valeur = convertir(request.getparameter("valeur")); if (valeur == null) throw new Exception("Champs valeur incorrect"); m.put(cle, valeur); else if (request.getparameter("supprimer")!= null) cle = convertir(request.getparameter("item")); if (cle == null) throw new Exception("Sélectionner un item"); m.remove(cle); RequestDispatcher dispatcher = request.getrequestdispatcher("/q5.jsp"); dispatcher.forward(request, response); catch (Exception e) ne codez pas cette partie, car elle est standard // dopost //class b) (3 pts) Donnez le code du ServletContextListener approprié. public void contextinitialized(servletcontextevent sce) sce.getservletcontext().setattribute("map",new HashMap()); 9/10
6) (10 pts) Définissez un DTD pour représenter les données du système décrit à la figure 1 page 3. Évitez la redondance; stockez une association une seule fois. <?xml version='1.0' encoding='iso-8859-1'?> <!ELEMENT q6 (tupleb*)> <!ELEMENT tupleb (tuplec*,r3*)> <!ATTLIST article b CDATA #REQUIRED c CDATA #REQUIRED > <!ELEMENT r3 (tuplea)> <!ELEMENT tuplea (EMPTY)> <!ATTLIST tuplea a CDATA #REQUIRED bder2 CDATA #IMPLIED > <!ELEMENT tuplec EMPTY> <!ATTLIST tuplec d CDATA #REQUIRED e CDATA #REQUIRED > 10/10