View Javadoc

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   * <p>A listener handler that will check for single parameter methods annotated with the given annotation.</p>
22   * <p>The default annotation for methods is {@link com.atlassian.event.api.EventListener}.</p>
23   *
24   * @see com.atlassian.event.api.EventListener
25   * @since 2.0
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  }