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.lang.reflect.Modifier;
23  import java.text.MessageFormat;
24  import at.ac.tuwien.infosys.sm4all.copal.api.event.ContextEvent;
25  import at.ac.tuwien.infosys.sm4all.copal.api.event.xml.Actions;
26  
27  /**
28   * Invoker of an {@link OnEvent} {@link Method}. For method to be considered an
29   * {@link OnEvent} {@link Method} all these conditions must be met:
30   * <ol>
31   * <li>{@link Method} must be annotated with {@link OnEvent}.</li>
32   * <li>{@link Method} must be public.</li>
33   * <li>{@link Method} must have exactly one parameter.</li>
34   * <li>The parameter of {@link Method} must be of type {@link ContextEvent} or a
35   * subclass of it.</li>
36   * </ol>
37   * 
38   * @author sanjin
39   */
40  public class OnEventMethod {
41  
42      private final Object listener;
43      private final Method method;
44      private final String type;
45      private final Class<?> parameter;
46  
47      /**
48       * Creates instance of invoker of specified {@link OnEvent} {@link Method}
49       * on specified listener.
50       * 
51       * @param listener the wrapped annotated listener.
52       * @param method the {@link OnEvent} {@link Method}.
53       * @throws NullPointerException if specified wrapped annotated listener or
54       *         {@link Method} is <code>null</code>.
55       * @throws IllegalArgumentException if specified {@link Method} has no
56       *         {@link OnEvent} annotation, is not public, has zero or more than
57       *         one parameter, or parameter is not {@link ContextEvent} or a
58       *         subclass of it.
59       */
60      public OnEventMethod(final Object listener, final Method method) {
61          super();
62  
63          if (listener == null)
64              throw new NullPointerException("Listener cannot be null.");
65          if (method == null)
66              throw new NullPointerException("Method cannot be null.");
67  
68          final String methodName = method.getName();
69          final OnEvent onEvent = method.getAnnotation(OnEvent.class);
70          if (onEvent == null)
71              throw new IllegalArgumentException(MessageFormat.format(
72                      "Method ''{0}'' has no OnEvent annotation.", methodName));
73          if (!Modifier.isPublic(method.getModifiers()))
74              throw new IllegalArgumentException(MessageFormat.format(
75                      "OnEvent method ''{0}'' is not public.", methodName));
76  
77          final Class<?>[] parameters = method.getParameterTypes();
78          if (parameters.length > 1)
79              throw new IllegalArgumentException(MessageFormat.format(
80                      "OnEvent method ''{0}'' has more than one parameter.",
81                      methodName));
82          if (parameters.length == 0)
83              throw new IllegalArgumentException(MessageFormat.format(
84                      "OnEvent method ''{0}'' has no parameters.", methodName));
85          if (!ContextEvent.class.isAssignableFrom(parameters[0]))
86              throw new IllegalArgumentException(
87                      MessageFormat.format(
88                              "Parameter of OnEvent method ''{0}'' is not ContextEvent or its subclass.",
89                              methodName));
90  
91          this.listener = listener;
92          this.method = method;
93          this.type = onEvent.type();
94          this.parameter = parameters[0];
95      }
96  
97      /**
98       * Returns the name of this {@link Actions} {@link Method}.
99       * 
100      * @return the name of this {@link Actions} {@link Method}.
101      * @see Method#getName()
102      */
103     public String getName() {
104         return this.method.getName();
105     }
106 
107     /**
108      * Returns type of {@link ContextEvent}s caught by this {@link OnEvent}
109      * {@link Method}.
110      * 
111      * @return type of {@link ContextEvent}s.
112      * @see OnEvent#type()
113      */
114     public String getType() {
115         return this.type;
116     }
117 
118     /**
119      * Returns type of parameter of this {@link OnEvent} {@link Method}.
120      * 
121      * @return type of parameter.
122      * @see Method#getParameterTypes()
123      */
124     public Class<?> getParameter() {
125         return this.parameter;
126     }
127 
128     /**
129      * Returns if specified {@link ContextEvent} can be passed as parameter to
130      * this {@link OnEvent} {@link Method}.
131      * 
132      * @param event the {@link ContextEvent}.
133      * @return if specified {@link ContextEvent} can be passed as parameter.
134      * @throws NullPointerException if specified {@link ContextEvent} is
135      *         <code>null</code>.
136      */
137     public boolean canBeInvokedWith(final ContextEvent event) {
138         if (event == null)
139             throw new NullPointerException("Event cannot be null.");
140 
141         return (OnEvent.ANY_TYPE.equals(this.type) || this.type.equals(event.getType().getName()))
142                 && this.parameter.isAssignableFrom(event.getClass());
143     }
144 
145     /**
146      * Invokes the underlying {@link OnEvent} {@link Method} with specified
147      * {@link ContextEvent}.
148      * 
149      * @param event the {@link ContextEvent}.
150      * @throws IllegalAccessException if this {@link OnEvent} {@link Method}
151      *         enforces Java language access control and the underlying method
152      *         is inaccessible.
153      * @throws InvocationTargetException if the underlying {@link OnEvent}
154      *         {@link Method} throws an {@link Exception}.
155      * @throws NullPointerException if specified {@link ContextEvent} is
156      *         <code>null</code>.
157      * @throws IllegalArgumentException if specified {@link ContextEvent} can
158      *         not be passed as parameter to this {@link OnEvent} {@link Method}
159      *         i.e. the {@link #canBeInvokedWith(ContextEvent)} method returns
160      *         <code>false</code>.
161      */
162     public void invoke(final ContextEvent event) throws IllegalAccessException,
163             InvocationTargetException {
164         if (event == null)
165             throw new NullPointerException("Event cannot be null.");
166 
167         if (canBeInvokedWith(event))
168             this.method.invoke(this.listener, event);
169         else
170             throw new IllegalArgumentException("Wrong event.");
171     }
172 }