View Javadoc

1   /* This file is part of COPAL (COntext Provisioning for All).
2    *
3    * COPAL is a part of SM4All (Smart hoMes for All) project.
4    *
5    * COPAL is free software: you can redistribute it and/or modify
6    * it under the terms of the GNU Lesser General Public License as published by
7    * the Free Software Foundation, either version 3 of the License, or
8    * (at your option) any later version.
9    *
10   * COPAL is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   * GNU Lesser General Public License for more details.
14   *
15   * You should have received a copy of the GNU Lesser General Public License
16   * along with COPAL. If not, see <http://www.gnu.org/licenses/>.
17   */
18  package at.ac.tuwien.infosys.sm4all.copal.api.listener;
19  
20  import java.lang.reflect.InvocationTargetException;
21  import java.lang.reflect.Method;
22  import java.text.MessageFormat;
23  import java.util.Collections;
24  import java.util.LinkedList;
25  import java.util.List;
26  import org.apache.log4j.Level;
27  import org.apache.log4j.Logger;
28  import at.ac.tuwien.infosys.sm4all.copal.api.event.ContextEvent;
29  import at.ac.tuwien.infosys.sm4all.copal.api.util.Name;
30  
31  /**
32   * Wrapper class that implements {@link ContextListener} around an
33   * {@link Object} which uses annotations to define its {@link Name} and
34   * {@link Events} {@link Method}s.
35   * 
36   * @author sanjin
37   */
38  public class AnnotatedListener extends BaseListener {
39  
40      private static final Logger LOGGER = Logger.getLogger(AnnotatedListener.class);
41  
42      private final List<EventsMethod> methods;
43  
44      /**
45       * Creates instance of wrapper {@link ContextListener} that wraps around
46       * specified annotated listener.
47       * 
48       * @param listener the annotated listener.
49       * @throws NullPointerException if specified annotated listener is
50       *         <code>null</code>.
51       * @throws IllegalArgumentException if specified annotated listener has no
52       *         {@link Name} annotation or there are no methods with
53       *         {@link Event} or {@link Events} annotations.
54       */
55      public AnnotatedListener(final Object listener) {
56          super(getName(listener));
57  
58          this.methods = getMethods(listener);
59          if (this.methods.isEmpty()) {
60              throw new IllegalArgumentException("No Events methods.");
61          }
62      }
63  
64      /**
65       * Invokes all {@link Events} {@link Method}s of the underlying annotated
66       * listener that can handle specified {@link ContextEvent}.
67       * 
68       * @param event the {@link ContextEvent}.
69       */
70      @Override
71      public void onEvent(final ContextEvent event) {
72          final String eventType = event.getType().getName();
73  
74          for (final EventsMethod method : this.methods) {
75              if (method.canBeInvokedWith(event)) {
76                  try {
77                      method.invoke(event);
78                  } catch (final InvocationTargetException ex) {
79                      if (LOGGER.isEnabledFor(Level.ERROR)) {
80                          LOGGER.error(
81                                  MessageFormat.format(
82                                          "Failed Events method ''{0}'' for event ''{1}'' in listener ''{2}''!",
83                                          method.getName(), eventType, getName()),
84                                  ex);
85                      }
86                  } catch (final IllegalAccessException ex) {
87                      if (LOGGER.isEnabledFor(Level.ERROR)) {
88                          LOGGER.error(
89                                  MessageFormat.format(
90                                          "Cannot invoke Events method ''{0}'' for event ''{1}'' in listener ''{2}''!",
91                                          method.getName(), eventType, getName()),
92                                  ex);
93                      }
94                  }
95              }
96          }
97      }
98  
99      private static List<EventsMethod> getMethods(final Object listener) {
100         if (null == listener) {
101             throw new IllegalArgumentException("Listener cannot be null.");
102         }
103 
104         final String name = getName(listener);
105         final List<EventsMethod> result = new LinkedList<EventsMethod>();
106 
107         for (final Method method : listener.getClass().getMethods()) {
108             if (null != method.getAnnotation(Event.class)) {
109                 try {
110                     result.add(new EventsMethod(listener, method));
111                 } catch (final IllegalArgumentException ex) {
112                     if (LOGGER.isEnabledFor(Level.WARN)) {
113                         LOGGER.warn(
114                                 MessageFormat.format(
115                                         "Malformed Events method ''{0}'' in listener ''{1}''!",
116                                         method.getName(), name), ex);
117                     }
118                 }
119             }
120         }
121 
122         return Collections.unmodifiableList(result);
123     }
124 
125     private static String getName(final Object listener) {
126         if (null == listener) {
127             throw new IllegalArgumentException("Listener cannot be null.");
128         }
129 
130         final Name name = listener.getClass().getAnnotation(Name.class);
131         if (null == name) {
132             throw new IllegalArgumentException(
133                     "Specified listener is not annotated with Name.");
134         }
135 
136         return name.value();
137     }
138 }