1 /* 2 * PCUServeur for the PCU project. 3 * Copyright (C) 2010 PLU Julien 4 * 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation, either version 3 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 * For questions: julien.plu@redaction-developpez.com 19 */ 20 package pcuserveur.lib; 21 22 import java.io.IOException; 23 import java.util.HashMap; 24 import java.util.Map.Entry; 25 26 /** 27 * @author PLU Julien 28 * @version 1.0 29 * 30 * <b> 31 * Un canal est un groupe de discussion plusieurs-à-plusieurs. 32 * Identifié par un nom, unique et sans espaces, il possède également 33 * un sujet qui le décrit brièvement, et la liste des gestionnaires de 34 * connexion formant le groupe. Sa signature est le triplet ( 35 * <code>nom</code>, "<code>sujet</code>", <code>nombreMembres</code>). 36 * </b> 37 * <p> 38 * Un Canal est caractérisé par les informations suivantes: 39 * <ul> 40 * <li>Une HashMap ayant un String pour clef et un 41 * GestionnaireConnexion pour valeur.</li> 42 * <li>Un String pour le nom du canal.</li> 43 * <li>Un String pour le sujet du canal.</li> 44 * </ul> 45 * </p> 46 * 47 * @see GestionnaireConnexion 48 * @see Evenement 49 * @see Serveur 50 * @see Vide 51 * @see DejaConnecteException 52 * @see NonConnecteException 53 */ 54 public class Canal implements Vide { 55 /** 56 * <p> 57 * Liste des connexions contenues dans le canal. 58 * </p> 59 * 60 * @see Canal#getSignature () 61 * @see Canal#ajouterGC (GestionnaireConnexion) 62 * @see Canal#enleverGC (GestionnaireConnexion) 63 * @see Canal#enleverGC (String) 64 * @see Canal#listerMembre () 65 * @see Canal#notifier (Evenement, String, String) 66 * @see Canal#vider () 67 */ 68 private final HashMap<String, GestionnaireConnexion> listeGestionnaires = new HashMap<String, GestionnaireConnexion> (); 69 /** 70 * <p> 71 * Nom du canal. 72 * </p> 73 * 74 * @see Canal#getNom () 75 * @see Canal#Canal (String, String) 76 * @see Canal#estVide () 77 * @see Canal#initialiser (String, String) 78 * @see Canal#notifier (Evenement, String, String) 79 * @see Canal#getSignature () 80 * @see Canal#vider () 81 */ 82 private String nom; 83 /** 84 * <p> 85 * Sujet du canal. 86 * </p> 87 * 88 * @see Canal#getSujet () 89 * @see Canal#Canal (String, String) 90 * @see Canal#changerSujet (String) 91 * @see Canal#estVide () 92 * @see Canal#initialiser (String, String) 93 * @see Canal#getSignature () 94 * @see Canal#vider () 95 */ 96 private String sujet; 97 98 /** 99 * <p> 100 * Constructeur par défaut. 101 * </p> 102 */ 103 public Canal () { 104 // Constructeur par défaut 105 } 106 107 /** 108 * <p> 109 * Constructeur paramétré. 110 * </p> 111 * 112 * @param nom1 113 * Le nom. 114 * @param sujet1 115 * Le sujet. 116 */ 117 public Canal (final String nom1, final String sujet1) { 118 this.nom = nom1; 119 this.sujet = sujet1; 120 } 121 122 /** 123 * <p> 124 * Ajoute un gestionnaire de connexion au canal. Après avoir ajouté 125 * <code>gc</code>, les autres membres du canal sont notifiés de son 126 * arrivée. 127 * </p> 128 * 129 * @param gc 130 * Le gestionnaire de connexion à ajouter. 131 * 132 * @throws DejaConnecteException 133 * <code>gc<code> est déjà dans le canal. 134 * @throws IOException 135 * Un envoie lors de la notification a échoué. 136 */ 137 public void ajouterGC (final GestionnaireConnexion gc) throws DejaConnecteException, IOException { 138 final String login = gc.getClient ().getLogin (); 139 140 if (!this.listeGestionnaires.containsKey (login)) { 141 this.listeGestionnaires.put (login, gc); 142 this.notifier (Evenement.REJOINT, login, ""); //$NON-NLS-1$ 143 } 144 else { 145 throw new DejaConnecteException (login + " est deja dans " + this.nom); //$NON-NLS-1$ 146 } 147 } 148 149 /** 150 * <p> 151 * Change le sujet du canal. Après avoir changé le sujet, les autres membres 152 * du canal sont notifiés du changement. 153 * </p> 154 * 155 * @param sujet1 156 * Le nouveau sujet. 157 * 158 * @throws IOException 159 * Un envoie lors de la notification a échoué. 160 */ 161 public void changerSujet (final String sujet1) throws IOException { 162 this.sujet = sujet1; 163 164 this.notifier (Evenement.SUJETCHANGE, "", sujet1); //$NON-NLS-1$ 165 } 166 167 /** 168 * <p> 169 * Enlève un gestionnaire de connexion du canal. Après avoir enlevé 170 * <code>gc</code>, les autres membres du canal sont notifiés de son départ. 171 * </p> 172 * 173 * @param gc 174 * Le gestionnaire de connexion à retirer. 175 * 176 * @throws NonConnecteException 177 * <code>gc</code> n'est pas dans le canal. 178 * @throws IOException 179 * Un envoie lors de la notification a échoué. 180 */ 181 public synchronized void enleverGC (final GestionnaireConnexion gc) throws NonConnecteException, IOException { 182 final String login = gc.getClient ().getLogin (); 183 184 if (this.listeGestionnaires.containsKey (login)) { 185 this.listeGestionnaires.remove (login); 186 this.notifier (Evenement.PARTI, login, ""); //$NON-NLS-1$ 187 } 188 else { 189 throw new NonConnecteException (login + " n'est pas dans " + this.nom); //$NON-NLS-1$ 190 } 191 } 192 193 /** 194 * <p> 195 * Enlève un gestionnaire de connexion du canal. Après avoir enlevé 196 * <code>login</code>, les autres membres du canal sont notifiés de son 197 * départ. 198 * </p> 199 * 200 * @param login 201 * Login du client à enlever. 202 * 203 * @throws NonConnecteException 204 * <code>login</code> n'est pas dans le canal. 205 */ 206 public synchronized void enleverGC (final String login) throws NonConnecteException { 207 if (this.listeGestionnaires.containsKey (login)) { 208 this.listeGestionnaires.remove (login); 209 } 210 else { 211 throw new NonConnecteException (login + " n'est pas dans " + this.nom); //$NON-NLS-1$ 212 } 213 } 214 215 /** 216 * <p> 217 * Savoir si le canal est vide. 218 * </p> 219 * 220 * @return <code>true</code> si le canal est vide, <code>false</code> sinon. 221 */ 222 public boolean estVide () { 223 return (this.nom == null) && (this.sujet == null); 224 } 225 226 /** 227 * <p> 228 * Obtenir le nom du canal, si il existe. 229 * </p> 230 * 231 * @return Le nom, ou <code>null</code> si le canal est vide. 232 */ 233 public String getNom () { 234 return this.nom; 235 } 236 237 /** 238 * <p> 239 * Obtenir la signature du canal. 240 * </p> 241 * 242 * @return La signature du canal, ou <code>null</code> si il est vide. 243 */ 244 public String getSignature () { 245 return this.estVide () ? null : this.nom + " \"" + this.sujet + "\" " + this.listeGestionnaires.size (); //$NON-NLS-1$ //$NON-NLS-2$ 246 } 247 248 /** 249 * <p> 250 * Obtenir le sujet du canal, si il existe. 251 * </p> 252 * 253 * @return Le sujet, ou <code>null</code> si le canal est vide. 254 */ 255 public String getSujet () { 256 return this.sujet; 257 } 258 259 /** 260 * <p> 261 * Initialise le canal, à la façon du constructeur paramétré. 262 * </p> 263 * 264 * @param nom1 265 * Le nom. 266 * @param sujet1 267 * Le sujet. 268 */ 269 public void initialiser (final String nom1, final String sujet1) { 270 this.nom = nom1; 271 this.sujet = sujet1; 272 } 273 274 /** 275 * <p> 276 * Initialise le canal, à la façon du constructeur paramétré. 277 * </p> 278 * 279 * @return la liste des membres du canal 280 */ 281 public String listerMembre () { 282 final StringBuffer res = new StringBuffer (); 283 int i = 0; 284 285 for (final Entry<String, GestionnaireConnexion> entry:this.listeGestionnaires.entrySet ()) { 286 final GestionnaireConnexion valeur = entry.getValue (); 287 288 res.append (valeur.getClient ().getLogin ()); 289 if (i != this.listeGestionnaires.size () - 1) { 290 res.append (" "); //$NON-NLS-1$ 291 } 292 i++; 293 } 294 295 return res.toString (); 296 } 297 298 /** 299 * <p> 300 * Notifie tous les membres du canal, d'un évènement l'affectant. 301 * </p> 302 * 303 * @param evenement 304 * L'événement à notifier. 305 * @param login 306 * Le login. Si il n'est pas pertinant, la chaîne est vide. 307 * @param texte 308 * Le texte. Si il n'est pas pertinant, la chaîne est vide. 309 * 310 * @throws IOException 311 * Un envoie lors de la notification a échoué. 312 */ 313 public synchronized void notifier (final Evenement evenement, final String login, final String texte) throws IOException { 314 for (final Entry<String, GestionnaireConnexion> entry:this.listeGestionnaires.entrySet ()) { 315 final GestionnaireConnexion valeur = entry.getValue (); 316 317 if (valeur != null) { 318 valeur.notifier (this.nom, evenement, login, texte); 319 } 320 } 321 } 322 323 /** 324 * <p> 325 * Vide le canal. Positionne le nom et le sujet à <code>null</code>, et 326 * supprime tous les éléments de la liste des gestionnaires de connexion. A 327 * utiliser avec beaucoup de précaution. 328 * </p> 329 * 330 * @see Vide 331 */ 332 public void vider () { 333 this.nom = null; 334 this.sujet = null; 335 this.listeGestionnaires.clear (); 336 } 337 }