package fr.iutfbleau.projetIHM2022FI2.MNP; import fr.iutfbleau.projetIHM2022FI2.API.*; import java.sql.Connection; import org.mariadb.jdbc.*; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.PreparedStatement; import java.sql.SQLException; import javax.swing.JFrame; import javax.swing.JOptionPane; import java.util.*; /** * Usine abstraite gérant l'ensemble des groupes. * */ public class AbstractGroupeFactoryNP implements AbstractGroupeFactory { // la racine (promotion) private Groupe promo; //la fentre pour les fenetre modale private JFrame fenetre; // On utilise une table de hachage pour retrouver facilement un groupe (à partir de son id). // Si il y a beaucoup de groupes c'est plus rapide que de parcourir toute une liste. private HashMap brain; /** * Le constructeur fabrique le groupe promotion déja plein (utilisé en Modèle persistant de donné). */ public AbstractGroupeFactoryNP(JFrame fenetre){ this.fenetre=fenetre; this.brain=new HashMap(); this.init(); } /** * Le constructeur fabrique le groupe promotion vide. * Il faut ensuite y ajouter les étudiants. */ public AbstractGroupeFactoryNP(String name, int min, int max, JFrame fenetre){ Objects.requireNonNull(name,"On ne peut pas créer une promotion dont le nom est null"); this.promo=new GroupeNP(name,min,max); this.fenetre=fenetre; this.brain=new HashMap(); this.brain.put(Integer.valueOf(this.promo.getId()),this.promo); this.saveGroupe(promo); } /** * Test plutôt optimiste. Si la clé est identique alors on fait comme si c'était le bon groupe. * * @return true si le groupe est connu */ public Boolean knows(Groupe g){ return this.brain.containsKey(Integer.valueOf(g.getId())); } public boolean changeNameGroupe(Groupe g, String name){ if(!this.knows(g)){ throw new IllegalArgumentException("Groupe inconu "); } Connection cnx=this.cnx(); try{ PreparedStatement pst=cnx.prepareStatement( "UPDATE `Groupe` SET `nom` = ? WHERE `Groupe`.`id` = ? " ); pst.setString(1, name); pst.setInt(2, g.getId()); pst.executeUpdate(); pst.close(); }catch(SQLException e){ System.out.println(e.toString()); if(this.erreurSQL()){ this.changeNameGroupe(g, name); }else{ return false; } } this.close(cnx); g.setName(name); return true; } /** * permet de récupérer le Groupe qui contient les étudiants de toute la promotion * @return la promo. */ public Groupe getPromotion(){ return this.promo; } /** * permet de supprimer un groupe connu de l'usine abstraite qui ne contient pas de groupes. * Pour détruire un groupe connu qui en contient d'autres il faut le faire récursivement. * * @throws java.lang.NullPointerException si un argument est null * @throws java.lang.IllegalStateException si le groupe contient des groupes * @throws java.lang.IllegalArgumentException si le groupe n'est pas connu de l'usine abstraite ou bien si le groupe est celui de toute la promotion (renvoyé par getPromotion) */ public void deleteGroupe(Groupe g){ Objects.requireNonNull(g,"On ne peut pas enlever un groupe null car null n'est pas un groupe autorisé"); if (!this.knows(g)){ throw new IllegalArgumentException("Impossible d'enlever un groupe inconnu"); } g.getPointPoint().removeSousGroupe(g); this.brain.remove(Integer.valueOf(g.getId())); this.suprGroupe(g); } /** * permet d'ajouter un groupe vide de type FREE comme sous-groupe d'un groupe donné. * @param pere le groupe père du groupe à créer * @param name le nom du groupe à créer * @param min,max bornes indicatives sur la taille du groupe à créer * * @throws java.lang.NullPointerException si un argument est null * @throws java.lang.IllegalArgumentException si le groupe pere est de type PARTITION * ou si il n'y a pas 0 < min <= max */ public void createGroupe(Groupe pere, String name, int min, int max){ Objects.requireNonNull(pere,"Le groupe pere ne peut pas être null"); Objects.requireNonNull(name,"Le nouveau groupe ne peut pas avoir null comme nom"); if (!this.knows(pere)){ throw new IllegalArgumentException("Interdit d'ajouter un fils à un groupe inconnu"); } if (pere.getType().equals(TypeGroupe.PARTITION)){ throw new IllegalArgumentException("Impossible d'ajouter un groupe à une parition. Il faut utiliser createPartition pour créer une partition"); } if ( min <= 0 || max < min){ throw new IllegalArgumentException("Il faut que 0 < min <= max"); } Groupe g = new GroupeNP(pere,name,min,max); pere.addSousGroupe(g); this.brain.put(Integer.valueOf(g.getId()),g); this.saveGroupe(g); } /** * permet de créer une partition automatiquement sous un groupe donné. * * @param pere le groupe père du groupe à partitionner * @param name le nom des groupe à créer (on ajoute à la suite un numéro de 1 à n pour distinguer chaque groupe formant la partition) * @param n le nombre de partitions * @throws java.lang.NullPointerException si un argument est null * @throws java.lang.IllegalArgumentException si le groupe pere est de type PARTITION * ou n négatif ou nul * * NB. doit créer une "copie" de pere * sous pere de type Partition et ajouter sous ce groupe, n groupes de type "FREE". * les valeurs min et max de ces n groupes sont * min = 0 et * max = partie entière de N/n plus 1, où N est le nombre max du groupe pere. */ public void createPartition(Groupe pere, String name, int n){ Objects.requireNonNull(pere,"Le groupe pere ne peut pas être null"); Objects.requireNonNull(name,"Le nouveau groupe ne peut pas avoir null comme nom"); if (!this.knows(pere)){ throw new IllegalArgumentException("Impossible de partitionner ce groupe inconnu"); } if (pere.getType().equals(TypeGroupe.PARTITION)){ throw new IllegalArgumentException("Impossible de créer une partition à ce niveau. Il faut soit repartitionner le groupe au dessus, soit partitionner une partition en dessous."); } if ( n <= 0){ throw new IllegalArgumentException("Le nombre de partitions doit être strictement positif"); } //Création de la racine de la partition. Groupe copiePereRacinePartition = new GroupeNP(pere); pere.addSousGroupe(copiePereRacinePartition); this.brain.put(Integer.valueOf(copiePereRacinePartition.getId()),copiePereRacinePartition); // création des sous-groupes int min = 0; int max = ((int) Math.floor(pere.getSize()/n))+1; List groupes = new ArrayList(n); for(int i = 0; i l'ensemble des étudiants connus de la factory ayant un nom "proche" de ce string au sens de la remarque ci-dessus. * * @throws java.lang.NullPointerException si le String est null. */ public Set getEtudiants(String nomEtu){ Set s=new LinkedHashSet<>(); //on retourne tous les etudiants if(nomEtu==null){ if(this.getPromotion()!=null){ for(Etudiant et:this.getPromotion().getEtudiants()){ s.add(et); } } //ceux qui sont connu mais pas dans la promo Connection cnx=this.cnx(); try{ PreparedStatement pst=cnx.prepareStatement("SELECT * FROM Etudiant where Etudiant.id NOT IN (SELECT CONTIENT.idEt FROM CONTIENT) Group by Etudiant.id;"); ResultSet rs=pst.executeQuery(); while(rs.next()){ s.add(new EtudiantNP(rs.getString(2), rs.getString(3), rs.getInt(1))); } }catch(SQLException e){ System.out.println(e.toString()); if(this.erreurCO()) return this.getEtudiants(nomEtu); return null; } this.close(cnx); }else{ for(Etudiant e:this.getPromotion().getEtudiants()){ if((e.getNom()).contains(nomEtu)){ s.add(e); } } } return s; } /** * permet de retrouver les groupes d'un étudiant. * * @param Etu un étudiant * @return Etudiant l'étudiant connu de la factory ayant cet identifiant * * @throws java.lang.NullPointerException si le String est null. */ public Set getGroupesOfEtudiant(Etudiant etu){ if(etu==null) throw new NullPointerException(); Set ret=new LinkedHashSet(); Connection cnx=this.cnx(); try{ PreparedStatement pst=cnx.prepareStatement("SELECT `idGroupe` FROM CONTIENT where idEt=? Group by `idGroupe`;"); pst.setInt(1, etu.getId()); ResultSet rs=pst.executeQuery(); while(rs.next()){ ret.add(this.brain.get(rs.getInt(1))); } rs.close(); pst.close(); }catch(SQLException e){ } this.close(cnx); return ret; } // ********************** // FONCTION POUR SIMPLIFIER LES Modification BD // *********************** private Connection cnx(){ //On se Connecte a la BD try{ Class.forName("org.mariadb.jdbc.Driver"); Connection cnx = DriverManager.getConnection( "jdbc:mariadb://dwarves.iut-fbleau.fr/chaignea", "chaignea", "Chaigneauphpmyadmin"); return cnx; }catch(Exception e){ System.out.println(e.toString()); if(this.erreurCO()==true){ return this.cnx(); } } return null; } private boolean erreurCO(){ if(JOptionPane.showConfirmDialog(this.fenetre, "erreur connection a la BD reassayer?", "erreur connection", JOptionPane.YES_NO_OPTION)==JOptionPane.YES_OPTION){ return true; }else{ this.fenetre.dispose(); return false; } } private boolean erreurSQL(){ if(JOptionPane.showConfirmDialog(this.fenetre, "erreur lors de la modification, reasssayer?", "erreur SQL", JOptionPane.YES_NO_OPTION)==JOptionPane.YES_OPTION){ return true; }else{ return false; } } private void deleteEtu(Etudiant et, Groupe g){ Connection cnx=this.cnx(); try{ PreparedStatement pst=cnx.prepareStatement( "DELETE FROM CONTIENT WHERE idGroupe=? AND idEt=?; " ); pst.setInt(2, et.getId()); this.deleteEtu(pst, cnx, g.getId()); pst.close(); }catch(SQLException e){ System.out.println(e.toString()); if(this.erreurSQL()){ this.deleteEtu(et, brain.get(g.getId())); } } this.close(cnx); } private void deleteEtu(PreparedStatement pst, Connection cnx, int id){ try{ pst.setInt(1, id); pst.executeUpdate(); PreparedStatement sous=cnx.prepareStatement( "SELECT * FROM Groupe WHERE `id-parent`=? AND `id-parent`!=id; " ); sous.setInt(1, id); ResultSet rs=sous.executeQuery(); while(rs.next()){ this.deleteEtu(pst, cnx, rs.getInt(1)); } }catch(SQLException e){ System.out.println(e.toString()); if(this.erreurSQL()){ this.deleteEtu(pst, cnx, id); } } } private void close(AutoCloseable clos){ try{ clos.close(); }catch(Exception e){ System.out.println(e.toString()); if(this.erreurCO()==true) this.close(clos); } } private boolean saveEtu(Etudiant etudiant, Groupe g){ Connection cnx = this.cnx(); try{ PreparedStatement pst=cnx.prepareStatement( "Select id from Etudiant where id=?; "); pst.setString(1, String.valueOf(etudiant.getId())); ResultSet rs=pst.executeQuery(); if(rs.next()){ //L'etudiant est déja connu de la BD pst.close(); pst=cnx.prepareStatement( "INSERT INTO `CONTIENT` (`idGroupe`, `idEt`) VALUES (?, ?);"); pst.setInt(2, etudiant.getId()); pst.setInt(1, g.getId()); pst.executeUpdate(); }else{ pst.close(); pst=cnx.prepareStatement( "INSERT INTO `Etudiant` (`id`, `nom`, `prenom`) VALUES (?, ?, ?) ;"); pst.setInt(1, etudiant.getId()); pst.setString(2, etudiant.getNom()); pst.setString(3, etudiant.getPrenom()); pst.executeUpdate(); } rs.close(); pst.close(); }catch(SQLException e){ System.out.println(e.toString()); if(this.erreurSQL()){ this.saveEtu(etudiant, g); }else{ return false; } } this.close(cnx); return true; } private boolean saveGroupe(Groupe g){ Connection cnx=this.cnx(); try{ PreparedStatement pst=cnx.prepareStatement( "INSERT INTO `Groupe` (`id`, `nom`, `min`, `max`, `Type`, `id-parent`) VALUES (?, ?, ?, ?, ?, ?);" ); pst.setInt(1, g.getId()); pst.setString(2, g.getName()); pst.setInt(3, g.getMin()); pst.setInt(4, g.getMax()); pst.setString(5, g.getType().name()); pst.setInt(6, g.getPointPoint().getId()); pst.executeUpdate(); pst.close(); for(Etudiant e: g.getEtudiants()){ this.saveEtu(e, g); } for(Groupe sous:g.getSousGroupes()){ this.saveGroupe(sous); } }catch(SQLException e){ System.out.println(e.toString()); if(this.erreurSQL()){ this.saveGroupe(g); }else{ return false; } } this.close(cnx); return true; } private boolean suprGroupe(Groupe g){ Connection cnx=this.cnx(); try{ PreparedStatement pst=cnx.prepareStatement("Delete FROM Groupe where id=?;"); pst.setInt(1, g.getId()); pst.executeUpdate(); pst.close(); pst=cnx.prepareStatement("Delete FROM CONTIENT where idGroupe=?;"); pst.setInt(1, g.getId()); pst.executeUpdate(); pst.close(); }catch(SQLException e){ System.out.println(e.toString()); if(this.erreurSQL()){ this.suprGroupe(g); }else{ return false; } } this.close(cnx); return true; } /***************************** * FONCTION POUR INITIALISER LA FACTORY AVEC LA BD * ******************************** */ private void init(){ Connection cnx=this.cnx(); //on récupère le Groupe de la BD n'ayant pas de Parent (La promo donc) try{ PreparedStatement pst = cnx.prepareStatement( "SELECT `id`, `nom`, `min`, `max`, `value`, `id-parent` FROM `Groupe` join `TYPE` on Groupe.Type=TYPE.name ORDER BY Groupe.id ASC;"); ResultSet rs = pst.executeQuery(); rs=pst.executeQuery(); //Si il existe bien une promotion if(rs.next()){ //On créer le groupe de promo this.promo=new GroupeNP(rs.getInt(1), rs.getString(2), rs.getInt(3), rs.getInt(4), TypeGroupe.getType(rs.getString(5)), null); //on ajoute au cerveau this.brain.put(this.promo.getId(), this.promo); //On lui ajoute tout ses sous-groupe this.addSousGroupe(this.promo, cnx); //On ajoute les étudiants: for(Groupe sous: this.brain.values()){ this.addBDEtudiant(sous, cnx); } }else{ //Si aucune ligne et donc pas de promo: this.promo=null; } rs.close(); pst.close(); }catch(SQLException e){ System.out.println(e.toString()); if(this.erreurCO()) this.init(); } this.close(cnx); } /** * Fonction recursive permettant de récuperrer les sous groupe a partir de la BD * @param g le groupe * @param cnx la connection a la BD (evite de la surcharger) * @param pourcent le pourcentage de ce groupe dans le chargement */ private void addSousGroupe(Groupe g, Connection cnx){ try{ //On récupere les Groupe qui ont le parent :g PreparedStatement pst= cnx.prepareStatement( "SELECT `id`, `nom`, `min`, `max`, `value`, `id-parent` FROM `Groupe` join `TYPE` on Groupe.Type=TYPE.name where Groupe.`id-parent`=? and Groupe.id!=Groupe.`id-parent`;"); pst.setString(1, String.valueOf(g.getId())); ResultSet rs=pst.executeQuery(); rs=pst.executeQuery(); //autrement si le groupe as des sous groupe while(rs.next()){ //on les ajoute Groupe nouveau=new GroupeNP(rs.getInt(1), rs.getString(2), rs.getInt(3), rs.getInt(4), TypeGroupe.getType(rs.getString(5)), g); //Si one le connait pas if(this.brain.get(nouveau.getId())==null){ this.brain.put(nouveau.getId(), nouveau); } g.addSousGroupe(nouveau); this.addSousGroupe(nouveau, cnx); //on ajoute les sous groupe des sous-groupe } rs.close(); }catch(SQLException e){ System.out.println(e); if(this.erreurCO()) this.addSousGroupe(g, cnx); } } /** * Fonction recursive ajoutant les étudiant aux groupe de la promo * @param g le groupe pour qui ajouter les Etudiant * @param cnx la connection (evite de surcharger la BD) */ private void addBDEtudiant(Groupe g, Connection cnx){ try{ //On récupère les etudiants contenue du groupe PreparedStatement pst; //Si c'est la promo pst= cnx.prepareStatement("SELECT Etudiant.nom, Etudiant.prenom, Etudiant.id FROM `CONTIENT` JOIN Etudiant on CONTIENT.idEt=Etudiant.id WHERE CONTIENT.idGroupe=? ORDER BY Etudiant.id ASC"); pst.setInt(1, g.getId()); ResultSet rs=pst.executeQuery(); //Pour tous les étudiants while(rs.next()){ boolean exist=false; //autrement on recupere l'etudiant for(Etudiant e: g.getPointPoint().getEtudiants()){ if(e.getId()==rs.getInt(3)){ exist=true; g.addEtudiant(e); break; } } if(exist==false){ g.addEtudiant(new EtudiantNP(rs.getString(1), rs.getString(2), rs.getInt(3))); } } rs.close(); pst.close(); }catch(SQLException e){ System.out.println(e.toString()); if(this.erreurCO()) this.addBDEtudiant(g, cnx); } } /******************* * FONCTION POUR REFRESH * ******************* */ /** * Refresh le groupe donnée pour le mettre a jour avec la Base de donnée * Si le groupe n'existe plus on retourne le groupe parent le plus proche existant encore * @param g le groupe a refresh * @return le groupe refresh */ private Groupe refreshGroupe(Groupe g, Connection cnx){ try{ PreparedStatement pst = cnx.prepareStatement( "SELECT `id`, `nom`, `min`, `max`, `value`, `id-parent` FROM `Groupe` join `TYPE` on Groupe.Type=TYPE.name where Groupe.`id`=? OR Groupe.`id-parent`=? ORDER BY Groupe.id ASC;"); pst.setString(1, String.valueOf(g.getId())); pst.setString(2, String.valueOf(g.getId())); ResultSet rs=pst.executeQuery(); if(rs.next()){ if(rs.getString(2)!=g.getName()){ g.setName(rs.getString(2)); } Set it=new LinkedHashSet<>(); for(Groupe gr:g.getSousGroupes()){ it.add(gr); } for(Groupe gr:it){ g.removeSousGroupe(gr); } Set et=new LinkedHashSet<>(); for(Etudiant gr:g.getEtudiants()){ et.add(gr); } for(Etudiant gr:et){ g.removeEtudiant(gr); } this.addSousGroupePasRecursif(g, cnx); }else{ if(g==g.getPointPoint()){ g=null; }else{ g=this.refreshGroupe(g.getPointPoint(), cnx); } } rs.close(); }catch(SQLException e){ System.out.println(e.toString()); if(this.erreurCO()) this.refreshGroupe(g, cnx); } return g; } /** * refresh le Groupe ainsi que ses etudiants * @param g le groupe * @return le groupe refresh/un parent si il a été refresh */ public Groupe refreshALL(Groupe g){ Connection cnx = this.cnx(); g=this.refreshGroupe(g, cnx); Set et=new LinkedHashSet<>(); for(Etudiant gr:g.getEtudiants()){ et.add(gr); } for(Etudiant gr:et){ g.removeEtudiant(gr); } this.addBDEtudiant(g, cnx); this.close(cnx); return g; } /** * Fonction recursive permettant de récuperrer les sous groupe a partir de la BD * @param g le groupe * @param cnx la connection a la BD (evite de la surcharger) * @param pourcent le pourcentage de ce groupe dans le chargement */ private void addSousGroupePasRecursif(Groupe g, Connection cnx){ try{ //On récupere les Groupe qui ont le parent :g PreparedStatement pst= cnx.prepareStatement( "SELECT `id`, `nom`, `min`, `max`, `value`, `id-parent` FROM `Groupe` join `TYPE` on Groupe.Type=TYPE.name where Groupe.`id-parent`=? and Groupe.id!=Groupe.`id-parent`;"); pst.setString(1, String.valueOf(g.getId())); ResultSet rs=pst.executeQuery(); rs=pst.executeQuery(); //autrement si le groupe as des sous groupe while(rs.next()){ //on les ajoute Groupe nouveau=new GroupeNP(rs.getInt(1), rs.getString(2), rs.getInt(3), rs.getInt(4), TypeGroupe.getType(rs.getString(5)), g); //Si one le connait pas if(this.brain.get(nouveau.getId())==null){ this.brain.put(nouveau.getId(), nouveau); } g.addSousGroupe(nouveau); //on ajoute les sous groupe des sous-groupe } rs.close(); }catch(SQLException e){ System.out.println(e.toString()); if(this.erreurCO()) this.addSousGroupe(g, cnx); } } }