View Javadoc

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