View Javadoc

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 }