1 package com.atlassian.event.internal;
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.Lists;
8 import com.google.common.collect.Maps;
9 import org.slf4j.Logger;
10 import org.slf4j.LoggerFactory;
11
12 import java.lang.reflect.Method;
13 import java.util.List;
14 import java.util.Map;
15 import java.util.Optional;
16
17 import static com.google.common.base.Preconditions.checkNotNull;
18 import static com.google.common.collect.Lists.newLinkedList;
19
20
21
22
23
24
25
26
27 public final class AnnotatedMethodsListenerHandler implements ListenerHandler {
28 private final Logger log = LoggerFactory.getLogger(this.getClass());
29
30 private final Class annotationClass;
31
32 public AnnotatedMethodsListenerHandler() {
33 this(EventListener.class);
34 }
35
36 public AnnotatedMethodsListenerHandler(Class annotationClass) {
37 this.annotationClass = checkNotNull(annotationClass);
38 }
39
40 public List<? extends ListenerInvoker> getInvokers(final Object listener) {
41 final Map<Method, Optional<String>> validMethods = getValidMethods(checkNotNull(listener));
42
43 if (validMethods.isEmpty()) {
44 log.debug("Couldn't find any valid listener methods on class <{}>", listener.getClass().getName());
45 }
46
47 return Lists.transform(newLinkedList(validMethods.entrySet()),
48 (Function<Map.Entry<Method, Optional<String>>, ListenerInvoker>) e
49 -> new SingleParameterMethodListenerInvoker(listener, e.getKey(), e.getValue()));
50 }
51
52 private Map<Method, Optional<String>> getValidMethods(Object listener) {
53 final Map<Method, Optional<String>> annotatedMethods = Maps.newLinkedHashMap();
54 for (Method method : listener.getClass().getMethods()) {
55 if (isValidMethod(method)) {
56 annotatedMethods.put(method, getScope(method));
57 }
58 }
59 return annotatedMethods;
60 }
61
62 private Optional<String> getScope(Method method) {
63 final EventListener annotation = method.getAnnotation(EventListener.class);
64 return Optional
65 .ofNullable(annotation)
66 .map(EventListener::scope)
67 .filter(scopeName -> !"".equals(scopeName));
68 }
69
70 private boolean isValidMethod(Method method) {
71 if (isAnnotated(method)) {
72 if (hasOneAndOnlyOneParameter(method)) {
73 return true;
74 } else {
75 throw new RuntimeException("Method <" + method + "> of class <" + method.getDeclaringClass() + "> " +
76 "is annotated with <" + annotationClass.getName() + "> but has 0 or more than 1 parameters! " +
77 "Listener methods MUST have 1 and only 1 parameter.");
78 }
79 }
80 return false;
81 }
82
83 @SuppressWarnings("unchecked")
84 private boolean isAnnotated(Method method) {
85 return method.getAnnotation(annotationClass) != null;
86 }
87
88 private boolean hasOneAndOnlyOneParameter(Method method) {
89 return method.getParameterTypes().length == 1;
90 }
91 }