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