View Javadoc

1   package cz.cuni.amis.utils.listener;
2   
3   import java.util.Map;
4   import java.util.Map.Entry;
5   import java.util.concurrent.ConcurrentHashMap;
6   import java.util.logging.Logger;
7   
8   /**
9    * Map of the listeners according to some key.
10   * <br><br>
11   * Comes in handy when you need the map of Listeners&lt;? extends Listener&gt; and work
12   * with them (otherwise you're doomed to write tedious and ugly for-cycles forever).
13   * <br><br>
14   * And believe me, you don't want to parametrize the class more further the 'Key'...
15   * ... just remember it must be used with instances of 'Listener' and Java-generics are hell.
16   *  
17   * 
18   * @author Jimmy
19   */
20  @SuppressWarnings("unchecked")
21  public class ListenersMap<Key> {
22  
23  	/**
24  	 * Map of the listeners, key is the event class where the listener is hooked to.
25  	 */
26  	private Map<Key, Listeners<IListener>> listenersMap = 
27  	 				new ConcurrentHashMap<Key, Listeners<IListener>>();
28  	
29  	private int listenersCount = 0;
30  	
31  	private Logger log;
32  	
33  	private String name;
34  	
35  	public Logger getLog() {
36  		return log;
37  	}
38  	
39  	private void setListenersLog(Key key, Listeners listeners) {
40  		listeners.setLog(log, name+key);
41  	}
42  
43  	public void setLog(Logger log, String name) {
44  		synchronized(listenersMap) {
45  			this.log = log;
46  			this.name = name;
47  			if (this.name == null) {
48  				this.name = "ListenersMap-";
49  			} else {
50  				this.name += "-";
51  			}
52  			for (Entry<Key, Listeners<IListener>> entry : listenersMap.entrySet()) {
53  				setListenersLog(entry.getKey(), entry.getValue());
54  			}
55  		}
56  	}
57  
58  	public void add(Key key, IListener listener) {
59  		synchronized(listenersMap) {
60  			Listeners<IListener> listeners = listenersMap.get(key);
61  			if (listeners == null) {
62  				listeners = new Listeners<IListener>();
63  				setListenersLog(key, listeners);
64  				listenersMap.put(key, listeners);
65  			}
66  			listeners.addWeakListener(listener);
67  			++listenersCount;
68  		}
69  	}
70  	
71  	public boolean isListening(IListener listener) {
72  		for (Key key : listenersMap.keySet()) {
73  			if (isListening(key, listener)) return true;
74  		}
75  		return false;
76  	}
77  	
78  	public boolean isListening(Key key, IListener listener) {
79  		Listeners<IListener> listeners = listenersMap.get(key);
80  		if (listeners == null) return false;
81  		return listeners.isEqualListening(listener);
82  	}
83  	
84  	public void remove(IListener listener) {
85  		for (Key key : listenersMap.keySet()) {
86  			remove(key, listener);
87  		}			
88  	}
89  	
90  	public void remove(Key key, IListener listener) {
91  		Listeners<IListener> listeners = listenersMap.get(key);
92  		if (listeners == null) return;
93  		listenersCount -= listeners.removeListener(listener);
94  		if (listeners.count() == 0) {
95  			synchronized(listenersMap) {
96  				if (listeners.count() == 0) {
97  					listenersMap.remove(key);
98  				}
99  			}
100 		}
101 	}
102 	
103 	public void notify(Listeners.ListenerNotifier<IListener> notifier) {
104 		for (Key key : listenersMap.keySet()) {
105 			notify(key, notifier);
106 		}			
107 	}
108 	
109 	public void notify(Key key, Listeners.ListenerNotifier<IListener> notifier) {
110 		Listeners<IListener> listeners = listenersMap.get(key);
111 		if (listeners == null) return;
112 		listeners.notify(notifier);
113 	}
114 	
115 	public boolean notifySafe(Listeners.ListenerNotifier<IListener> notifier, Logger exceptionLog) {
116 		boolean noException = true;
117 		for (Key key : listenersMap.keySet()) {
118 			noException = notifySafe(key, notifier, exceptionLog) && noException;
119 		}			
120 		return noException;
121 	}
122 	
123 	public boolean notifySafe(Key key, Listeners.ListenerNotifier<IListener> notifier, Logger exceptionLog) {
124 		Listeners<IListener> listeners = listenersMap.get(key);
125 		if (listeners == null) return true;
126 		return listeners.notifySafe(notifier, exceptionLog);
127 	}
128 	
129 	/**
130 	 * Notice that "hasListeners" may report true even if there are no listeners registered here (because 
131 	 * of weak references). But it will usually return correct value.
132 	 * @return
133 	 */
134 	public boolean hasListeners() {
135 		return listenersCount > 0;
136 	}
137 	
138 }