1 package com.atlassian.event.spring;
2
3 import com.atlassian.event.api.EventListenerRegistrar;
4 import com.atlassian.event.config.ListenerHandlersConfiguration;
5 import com.atlassian.event.spi.ListenerHandler;
6 import com.atlassian.plugin.ModuleDescriptor;
7 import com.atlassian.plugin.Plugin;
8 import com.atlassian.plugin.event.PluginEventListener;
9 import com.atlassian.plugin.event.events.PluginDisabledEvent;
10 import com.atlassian.plugin.event.events.PluginModuleDisabledEvent;
11 import com.atlassian.plugin.event.events.PluginModuleEnabledEvent;
12 import com.atlassian.plugin.eventlistener.descriptors.EventListenerModuleDescriptor;
13 import com.atlassian.plugin.osgi.factory.descriptor.ComponentImportModuleDescriptor;
14 import com.google.common.collect.HashMultimap;
15 import com.google.common.collect.ImmutableSet;
16 import com.google.common.collect.Maps;
17 import com.google.common.collect.Multimap;
18 import org.slf4j.Logger;
19 import org.slf4j.LoggerFactory;
20 import org.springframework.beans.BeansException;
21 import org.springframework.beans.factory.BeanFactory;
22 import org.springframework.beans.factory.BeanFactoryAware;
23 import org.springframework.beans.factory.NoSuchBeanDefinitionException;
24 import org.springframework.beans.factory.config.ConfigurableBeanFactory;
25 import org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor;
26 import org.springframework.context.ApplicationEvent;
27 import org.springframework.context.ApplicationListener;
28 import org.springframework.context.event.ContextRefreshedEvent;
29 import org.springframework.core.Ordered;
30
31 import java.util.Collection;
32 import java.util.Map;
33 import java.util.Set;
34
35 import static com.google.common.base.Preconditions.checkNotNull;
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66 public class EventListenerRegistrarBeanProcessor implements DestructionAwareBeanPostProcessor, BeanFactoryAware, Ordered, ApplicationListener {
67
68
69
70
71
72
73 private static final Set<String> BLACKLISTED_PLUGIN_KEYS = ImmutableSet.of(
74 "com.atlassian.upm.atlassian-universal-plugin-manager-plugin",
75 "com.atlassian.activeobjects.activeobjects-plugin",
76 "com.atlassian.applinks.applinks-plugin",
77 "com.atlassian.crowd.embedded.admin",
78 "com.atlassian.oauth.admin",
79 "com.atlassian.oauth.consumer",
80 "com.atlassian.oauth.consumer.sal",
81 "com.atlassian.oauth.serviceprovider",
82 "com.atlassian.oauth.serviceprovider.sal",
83 "com.atlassian.plugins.rest.atlassian-rest-module",
84 "com.atlassian.soy.soy-template-plugin",
85 "com.atlassian.templaterenderer.api",
86 "com.atlassian.templaterenderer.atlassian-template-renderer-velocity1.6-plugin",
87 "com.atlassian.auiplugin"
88 );
89
90 private static final Logger LOG = LoggerFactory.getLogger(EventListenerRegistrarBeanProcessor.class);
91
92 private final String eventListenerRegistrarBeanName;
93 private final ListenerHandlersConfiguration listenerHandlersConfiguration;
94
95 private final Map<String, Object> listenersToBeRegistered = Maps.newHashMap();
96 private final Multimap<String, Object> eventListenersFromPlugins = HashMultimap.create();
97
98 private ConfigurableBeanFactory beanFactory;
99 private EventListenerRegistrar eventListenerRegistrar;
100 private boolean ignoreFurtherBeanProcessing;
101
102 public EventListenerRegistrarBeanProcessor(String eventListenerRegistrarBeanName, ListenerHandlersConfiguration listenerHandlersConfiguration) {
103 this.eventListenerRegistrarBeanName = checkNotNull(eventListenerRegistrarBeanName);
104 this.listenerHandlersConfiguration = checkNotNull(listenerHandlersConfiguration);
105 }
106
107 @Override
108 public int getOrder() {
109
110 return 1;
111 }
112
113 @PluginEventListener
114 public void onPluginModuleEnabled(PluginModuleEnabledEvent event) {
115 Plugin plugin = event.getModule().getPlugin();
116
117 if (BLACKLISTED_PLUGIN_KEYS.contains(plugin.getKey())) {
118 return;
119 }
120
121 ModuleDescriptor moduleDescriptor = event.getModule();
122
123 if (isSuitablePluginModule(moduleDescriptor)) {
124
125
126
127 if (moduleDescriptorReturnsNewInstanceEveryTime(moduleDescriptor)) {
128 return;
129 }
130
131 try {
132 Object module = moduleDescriptor.getModule();
133
134 try {
135 if (canBeRegisteredAsAListener(moduleDescriptor.getKey(), module)) {
136 eventListenersFromPlugins.put(plugin.getKey(), module);
137 registerListener(moduleDescriptor.getKey(), module);
138 }
139 } catch (Throwable t) {
140 if (!(t instanceof NoClassDefFoundError)) {
141 LOG.info("Error registering eventlisteners for module " + moduleDescriptor
142 .getCompleteKey() + "; skipping.", t);
143 } else {
144 LOG.debug("Skipping " + moduleDescriptor
145 .getCompleteKey() + " because not all referenced classes are visible from" +
146 " the classloader.");
147 }
148 }
149 } catch (Exception e) {
150
151 return;
152 }
153 }
154 }
155
156 private static boolean isSuitablePluginModule(ModuleDescriptor moduleDescriptor) {
157 final Class<? extends ModuleDescriptor> moduleDescriptorClass = moduleDescriptor.getClass();
158 final Class moduleClass = moduleDescriptor.getModuleClass();
159
160 return !moduleDescriptorClass.equals(ComponentImportModuleDescriptor.class)
161 && moduleClass != null
162 && !moduleClass.equals(Void.class)
163 && !(moduleDescriptor instanceof EventListenerModuleDescriptor);
164 }
165
166 @PluginEventListener
167 public void onPluginDisabled(PluginDisabledEvent event) {
168 Plugin plugin = event.getPlugin();
169 Collection<Object> listeners = eventListenersFromPlugins.get(plugin.getKey());
170 if (listeners != null) {
171 for (Object eventListener : listeners) {
172 eventListenerRegistrar.unregister(eventListener);
173 }
174 eventListenersFromPlugins.removeAll(plugin.getKey());
175 }
176 }
177
178 @PluginEventListener
179 public void onPluginModuleDisabled(PluginModuleDisabledEvent event) {
180 ModuleDescriptor moduleDescriptor = event.getModule();
181 Object module = null;
182 try {
183 module = moduleDescriptor.getModule();
184 } catch (Exception e) {
185
186 }
187 if (module != null && eventListenersFromPlugins.remove(moduleDescriptor.getPluginKey(), module)) {
188 eventListenerRegistrar.unregister(module);
189 }
190 }
191
192 private static boolean moduleDescriptorReturnsNewInstanceEveryTime(ModuleDescriptor moduleDescriptor) {
193 return moduleDescriptor.getModule() != moduleDescriptor.getModule();
194 }
195
196 @Override
197 public void onApplicationEvent(ApplicationEvent applicationEvent) {
198 if (applicationEvent instanceof ContextRefreshedEvent) {
199
200
201 ignoreFurtherBeanProcessing = true;
202 }
203 }
204
205 @Override
206 public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
207 if (beanName.equals(eventListenerRegistrarBeanName)) {
208 eventListenerRegistrar = (EventListenerRegistrar) bean;
209 if (isAListener(this)) {
210
211 eventListenerRegistrar.register(this);
212 }
213
214 for (Object object : listenersToBeRegistered.values()) {
215 eventListenerRegistrar.register(object);
216 }
217
218 listenersToBeRegistered.clear();
219 }
220 return bean;
221 }
222
223 @Override
224 public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
225 unregisterListener(bean, beanName);
226 }
227
228 @Override
229 public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
230 if (!ignoreFurtherBeanProcessing && canBeRegisteredAsAListener(beanName, bean)) {
231 registerListener(beanName, bean);
232 }
233 return bean;
234 }
235
236 private boolean canBeRegisteredAsAListener(String beanName, Object bean) {
237 if (isAListener(bean)) {
238 try {
239
240
241 return beanFactory.getMergedBeanDefinition(beanName).isSingleton();
242 } catch (NoSuchBeanDefinitionException e) {
243
244 return true;
245 }
246 } else {
247 return false;
248 }
249 }
250
251 @Override
252 public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
253 this.beanFactory = (ConfigurableBeanFactory) beanFactory;
254 }
255
256 private void registerListener(String beanName, Object bean) {
257 LOG.debug("Registering {} instance as an eventlistener", beanName);
258 if (eventListenerRegistrar != null) {
259 eventListenerRegistrar.register(bean);
260 } else {
261 listenersToBeRegistered.put(beanName, bean);
262 }
263 }
264
265 private void unregisterListener(Object bean, String beanName) {
266 if (eventListenerRegistrar != null) {
267 eventListenerRegistrar.unregister(bean);
268 } else {
269 listenersToBeRegistered.remove(beanName);
270 }
271 }
272
273 private boolean isAListener(Object object) {
274 for (ListenerHandler handler : listenerHandlersConfiguration.getListenerHandlers()) {
275 if (!handler.getInvokers(object).isEmpty()) {
276 return true;
277 }
278 }
279 return false;
280 }
281 }