1 /* 2 * #%L 3 * Nuiton Utils 4 * %% 5 * Copyright (C) 2004 - 2010 CodeLutin 6 * %% 7 * This program is free software: you can redistribute it and/or modify 8 * it under the terms of the GNU Lesser General Public License as 9 * published by the Free Software Foundation, either version 3 of the 10 * License, or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Lesser Public License for more details. 16 * 17 * You should have received a copy of the GNU General Lesser Public 18 * License along with this program. If not, see 19 * <http://www.gnu.org/licenses/lgpl-3.0.html>. 20 * #L% 21 */ 22 23 /* * 24 * ListenerSet.java 25 * 26 * Created: 10 mai 2004 27 * 28 * @author Benjamin Poussin - poussin@codelutin.com 29 * Copyright Code Lutin 30 * 31 * 32 * Mise a jour: $Date$ 33 * par : */ 34 package org.nuiton.util; 35 36 import java.beans.Statement; 37 import java.lang.ref.Reference; 38 import java.util.HashSet; 39 import java.util.Iterator; 40 41 /** 42 * <p>Cette classe permet de mettre en place facilement le support de listeners. 43 * Elle ne permet d'ajouter qu'une seul fois le meme listener. Si elle est 44 * la derniere à avoir une référence sur le listener, le listener est supprimé 45 * de la liste des listeners.</p> 46 * <p>Si on souhaite avoir une vérification sur le type de listener ajouté 47 * il faut utiliser le constructeur qui prend une classe en paramètre. Dans ce 48 * cas la méthode {@link #add(Object)} vérifie que l'object passé est bien 49 * du type ou un enfant du type donné en paramètre du constructeur 50 * <p>Il y a deux façon de prévenir les listeners d'un event soit par le 51 * mécanisme inclu dans cette classe en utilisant la méthode {@link #fire} soit 52 * en utilisant soit même l'Iterateur sur les listeners encore valide.</p> 53 * <pre> 54 * ListenerSet listeners = new ListenerSet(); 55 * ... 56 * listeners.fire("monEvent", MonObjetEvent); 57 * </pre> 58 * ou bien 59 * <pre> 60 * ListenerSet listeners = new ListenerSet(); 61 * ... 62 * for(Iterator i=listeners.iterator(); i.hasNext();){ 63 * MonListener l = (MonListener)i.next(); 64 * l.monEvent(MonObjetEvent); 65 * } 66 * </pre> 67 * Cette deuxième façon de faire est plus sûr car elle n'utilise pas 68 * l'introspection et donc une vérification est faite sur le nom de la méthode 69 * à appeler à la compilation, mais elle est plus verbeuse à écrire. 70 * 71 * @param <L> listeners type 72 * @see CategorisedListenerSet 73 */ 74 public class ListenerSet<L> implements Iterable<L> { // ListenerSet 75 76 /** Listeners reference set. */ 77 protected HashSet<Reference<L>> listeners = new HashSet<Reference<L>>(); 78 79 public int size() { 80 return listeners.size(); 81 } 82 83 /** 84 * Ajoute un listener dans la liste des listeners. 85 * 86 * @param l le listener à ajouter. Si l'objet passé est null, rien n'est fait 87 * si l'objet n'est pas du type passé en argument du constructeur 88 * une IllegalArgumentException est levée. 89 */ 90 public void add(L l) { 91 if (l == null) { 92 return; 93 } 94 95 TransparenteWeakReference<L> ref = new TransparenteWeakReference<L>(l); 96 listeners.add(ref); 97 } 98 99 /** 100 * ajoute tous les listeners d'un ListenerSet 101 * 102 * @param ls The feature to be added to the All attribute 103 */ 104 public void addAll(ListenerSet<L> ls) { 105 listeners.addAll(ls.listeners); 106 } 107 108 /** 109 * Appel la méthode du listener en passant l'objet event en paramètre 110 * Cette méthode echoue si la methode ou l'objet contenant la methode a 111 * appeler n'est pas public 112 * 113 * @param methodName le nom de la methode a appeler 114 * @param event l'event a passer en parametre de la methode a appeler 115 * @throws Exception si un des listeners leve une exception lors de l'appel 116 */ 117 public void fire(String methodName, Object event) throws Exception { 118 for (Iterator<L> i = iterator(); i.hasNext(); ) { 119 L o = i.next(); 120 Statement stm = new Statement(o, methodName, new Object[]{event}); 121 stm.execute(); 122 } 123 } 124 125 /** 126 * Appele la méthode du listener sans argument. 127 * 128 * Cette méthode echoue si la methode ou l'objet contenant la methode a 129 * appeler n'est pas public. 130 * 131 * @param methodName le nom de la methode a appeler 132 * @throws Exception si un des listeners leve une exception lors de l'appel 133 */ 134 public void fire(String methodName) throws Exception { 135 for (Iterator<L> i = iterator(); i.hasNext(); ) { 136 L o = i.next(); 137 Statement stm = new Statement(o, methodName, null); 138 stm.execute(); 139 } 140 } 141 142 /** 143 * Get iterator on listener list. 144 * 145 * @return iterator on listener list. 146 */ 147 public Iterator<L> iterator() { 148 return new ReferenceIterator<L>(listeners.iterator()); 149 } 150 151 /** 152 * Remove listener. 153 * 154 * @param l listener to remove 155 */ 156 public void remove(L l) { 157 TransparenteWeakReference<L> ref = new TransparenteWeakReference<L>(l); 158 listeners.remove(ref); 159 } 160 161 @Override 162 public String toString() { 163 return listeners.toString(); 164 } 165 166 /** Iterator qui supprime les references vides lors du parcours */ 167 static class ReferenceIterator<T> implements Iterator<T> { 168 /** DOCUMENTME Description of the Field */ 169 protected Iterator<Reference<T>> iter = null; 170 171 /** DOCUMENTME Description of the Field */ 172 protected T nextObject = null; 173 174 /** 175 * Un iterator contenant des References 176 * 177 * @param iter DOCUMENTME Description of the Parameter 178 */ 179 public ReferenceIterator(Iterator<Reference<T>> iter) { 180 this.iter = iter; 181 findNext(); 182 } 183 184 /** DOCUMENTME Method */ 185 protected void findNext() { 186 while (iter.hasNext() && nextObject == null) { 187 Reference<T> ref = iter.next(); 188 T o = ref.get(); 189 if (o != null) { 190 nextObject = o; 191 } else { 192 iter.remove(); 193 } 194 } 195 } 196 197 /** 198 * DOCUMENTME Method 199 * 200 * @return DOCUMENTME Description of the Return Value 201 */ 202 public boolean hasNext() { 203 return nextObject != null; 204 } 205 206 /** 207 * DOCUMENTME Method 208 * 209 * @return DOCUMENTME Description of the Return Value 210 */ 211 public T next() { 212 T result = nextObject; 213 nextObject = null; 214 findNext(); 215 return result; 216 } 217 218 /** DOCUMENTME Method */ 219 public void remove() { 220 iter.remove(); 221 } 222 } 223 224 } // ListenerSet