1 package com.atlassian.plugin.event.impl;
2
3 import com.atlassian.event.api.EventListener;
4 import com.atlassian.event.spi.ListenerHandler;
5 import com.atlassian.event.spi.ListenerInvoker;
6 import com.google.common.base.Function;
7 import com.google.common.collect.Iterables;
8 import com.google.common.collect.Lists;
9 import com.google.common.collect.Sets;
10
11 import java.lang.reflect.InvocationTargetException;
12 import java.lang.reflect.Method;
13 import java.util.List;
14 import java.util.Optional;
15 import java.util.Set;
16
17 import static com.google.common.base.Preconditions.checkNotNull;
18
19
20
21
22
23
24
25 final class MethodSelectorListenerHandler implements ListenerHandler {
26 private final ListenerMethodSelector listenerMethodSelector;
27
28 public MethodSelectorListenerHandler(ListenerMethodSelector listenerMethodSelector) {
29 this.listenerMethodSelector = listenerMethodSelector;
30 }
31
32 public List<? extends ListenerInvoker> getInvokers(final Object listener) {
33 final List<Method> validMethods = getValidMethods(checkNotNull(listener));
34
35 return Lists.newArrayList(Iterables.transform(validMethods, new Function<Method, ListenerInvoker>() {
36 public ListenerInvoker apply(final Method method) {
37 return new ListenerInvoker() {
38 @Override
39 public Set<Class<?>> getSupportedEventTypes() {
40 return Sets.newHashSet(method.getParameterTypes());
41 }
42
43 @Override
44 public void invoke(Object event) {
45 try {
46 method.invoke(listener, event);
47 } catch (IllegalAccessException e) {
48 throw new RuntimeException(e);
49 } catch (InvocationTargetException e) {
50 if (e.getCause() == null) {
51 throw new RuntimeException(e);
52 } else if (e.getCause().getMessage() == null) {
53 throw new RuntimeException(e.getCause());
54 } else {
55 throw new RuntimeException(e.getCause().getMessage(), e);
56 }
57 }
58 }
59
60 @Override
61 public Optional<String> getScope() {
62 final EventListener annotation = method.getAnnotation(EventListener.class);
63 return Optional
64 .ofNullable(annotation)
65 .map(EventListener::scope)
66 .filter(scopeName -> !"".equals(scopeName));
67 }
68
69 @Override
70 public boolean supportAsynchronousEvents() {
71 return true;
72 }
73 };
74 }
75 }));
76 }
77
78 private List<Method> getValidMethods(Object listener) {
79 final List<Method> listenerMethods = Lists.newArrayList();
80 for (Method method : listener.getClass().getMethods()) {
81 if (isValidMethod(method)) {
82 listenerMethods.add(method);
83 }
84 }
85 return listenerMethods;
86 }
87
88 private boolean isValidMethod(Method method) {
89 if (listenerMethodSelector.isListenerMethod(method)) {
90 if (hasOneAndOnlyOneParameter(method)) {
91 return true;
92 } else {
93 throw new RuntimeException("Method <" + method + "> of class <" + method.getDeclaringClass() + "> " +
94 "is being registered as a listener but has 0 or more than 1 parameters! " +
95 "Listener methods MUST have 1 and only 1 parameter.");
96 }
97 }
98 return false;
99 }
100
101 private boolean hasOneAndOnlyOneParameter(Method method) {
102 return method.getParameterTypes().length == 1;
103 }
104 }