1 package com.atlassian.plugin.event.impl;
2
3 import com.atlassian.plugin.event.PluginEventManager;
4 import com.atlassian.plugin.util.ClassUtils;
5
6 import java.lang.reflect.Method;
7 import java.lang.reflect.InvocationTargetException;
8 import java.util.*;
9
10 import org.apache.commons.collections.map.LazyMap;
11 import org.apache.commons.collections.Factory;
12 import org.apache.commons.logging.Log;
13 import org.apache.commons.logging.LogFactory;
14 import org.apache.commons.lang.Validate;
15
16
17
18
19
20 public class DefaultPluginEventManager implements PluginEventManager
21 {
22 private final Map<Class,Set<Listener>> eventsToListener;
23 private static final Log log = LogFactory.getLog(DefaultPluginEventManager.class);
24 private final ListenerMethodSelector[] listenerMethodSelectors;
25
26
27
28
29 public DefaultPluginEventManager()
30 {
31 this(new ListenerMethodSelector[]{new MethodNameListenerMethodSelector(), new AnnotationListenerMethodSelector()});
32 }
33
34
35
36
37
38 public DefaultPluginEventManager(ListenerMethodSelector[] selectors)
39 {
40 this.listenerMethodSelectors = selectors;
41 eventsToListener = LazyMap.decorate(new HashMap<Class,Set<Listener>>(), new Factory() {
42 public Set<Listener> create() { return new HashSet<Listener>(); }
43 });
44 }
45
46
47
48
49
50
51 public synchronized void broadcast(Object event)
52 {
53 Validate.notNull(event, "The event to broadcast must not be null");
54 final Set<Listener> calledListeners = new HashSet<Listener>();
55 for (Class type : ClassUtils.findAllTypes(event.getClass()))
56 {
57 Set<Listener> registrations = eventsToListener.get(type);
58 for (Listener reg : registrations)
59 {
60 if (calledListeners.contains(reg))
61 continue;
62 calledListeners.add(reg);
63 reg.notify(event);
64 }
65 }
66 }
67
68
69
70
71
72
73
74
75 public synchronized void register(Object listener) throws IllegalArgumentException
76 {
77 if (listener == null)
78 throw new IllegalArgumentException("Listener cannot be null");
79
80 forEveryListenerMethod(listener, new ListenerMethodHandler()
81 {
82 public void handle(Object listener, Method m)
83 {
84 if (m.getParameterTypes().length != 1)
85 throw new IllegalArgumentException("Listener methods must only have one argument");
86 Set<Listener> listeners = eventsToListener.get(m.getParameterTypes()[0]);
87 listeners.add(new Listener(listener, m));
88 }
89 });
90 }
91
92
93
94
95
96 public synchronized void unregister(Object listener)
97 {
98 forEveryListenerMethod(listener, new ListenerMethodHandler()
99 {
100 public void handle(Object listener, Method m)
101 {
102 Set<Listener> listeners = eventsToListener.get(m.getParameterTypes()[0]);
103 listeners.remove(new Listener(listener, m));
104 }
105 });
106 }
107
108
109
110
111
112
113 void forEveryListenerMethod(Object listener, ListenerMethodHandler handler)
114 {
115 Method[] methods = listener.getClass().getMethods();
116 for (int x=0; x<methods.length; x++)
117 {
118 Method m = methods[x];
119 for (int s = 0; s<listenerMethodSelectors.length; s++)
120 {
121 ListenerMethodSelector selector = listenerMethodSelectors[s];
122 if (selector.isListenerMethod(m))
123 {
124 handler.handle(listener, m);
125 }
126 }
127 }
128 }
129
130
131
132
133
134
135
136 private static interface ListenerMethodHandler
137 {
138 void handle(Object listener, Method m);
139 }
140
141 private static class Listener
142 {
143
144 public final Object listener;
145
146 public final Method method;
147
148 public Listener(Object listener, Method method)
149 {
150 Validate.notNull(listener);
151 Validate.notNull(method);
152 this.listener = listener;
153 this.method = method;
154 }
155
156 public void notify(Object event)
157 {
158 Validate.notNull(event);
159 try
160 {
161 method.invoke(listener, event);
162 }
163 catch (IllegalAccessException e)
164 {
165 log.error("Unable to access listener method: "+method, e);
166 }
167 catch (InvocationTargetException e)
168 {
169 log.error("Exception calling listener method", e.getCause());
170 }
171 }
172
173 public boolean equals(Object o)
174 {
175 if (this == o) return true;
176 if (o == null || getClass() != o.getClass()) return false;
177
178 Listener that = (Listener) o;
179
180 if (!listener.equals(that.listener)) return false;
181 if (!method.equals(that.method)) return false;
182
183 return true;
184 }
185
186 public int hashCode()
187 {
188 int result;
189 result = listener.hashCode();
190 result = 31 * result + method.hashCode();
191 return result;
192 }
193 }
194 }