View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
4   //  ------------------------------------------------------------------------
5   //  All rights reserved. This program and the accompanying materials
6   //  are made available under the terms of the Eclipse Public License v1.0
7   //  and Apache License v2.0 which accompanies this distribution.
8   //
9   //      The Eclipse Public License is available at
10  //      http://www.eclipse.org/legal/epl-v10.html
11  //
12  //      The Apache License v2.0 is available at
13  //      http://www.opensource.org/licenses/apache2.0.php
14  //
15  //  You may elect to redistribute this code under either of these licenses.
16  //  ========================================================================
17  //
18  
19  package org.eclipse.jetty.websocket.common.events.annotated;
20  
21  import java.lang.annotation.Annotation;
22  import java.lang.reflect.Method;
23  import java.lang.reflect.Modifier;
24  
25  import org.eclipse.jetty.websocket.api.InvalidWebSocketException;
26  import org.eclipse.jetty.websocket.common.events.ParamList;
27  
28  /**
29   * Basic scanner for Annotated Methods
30   * @param <T> The type of metadata
31   */
32  public abstract class AbstractMethodAnnotationScanner<T>
33  {
34      protected void assertIsPublicNonStatic(Method method)
35      {
36          int mods = method.getModifiers();
37          if (!Modifier.isPublic(mods))
38          {
39              StringBuilder err = new StringBuilder();
40              err.append("Invalid declaration of ");
41              err.append(method);
42              err.append(System.lineSeparator());
43  
44              err.append("Method modifier must be public");
45  
46              throw new InvalidWebSocketException(err.toString());
47          }
48  
49          if (Modifier.isStatic(mods))
50          {
51              StringBuilder err = new StringBuilder();
52              err.append("Invalid declaration of ");
53              err.append(method);
54              err.append(System.lineSeparator());
55  
56              err.append("Method modifier may not be static");
57  
58              throw new InvalidWebSocketException(err.toString());
59          }
60      }
61  
62      protected void assertIsReturn(Method method, Class<?> type)
63      {
64          if (!type.equals(method.getReturnType()))
65          {
66              StringBuilder err = new StringBuilder();
67              err.append("Invalid declaration of ");
68              err.append(method);
69              err.append(System.lineSeparator());
70  
71              err.append("Return type must be ").append(type);
72  
73              throw new InvalidWebSocketException(err.toString());
74          }
75      }
76  
77      protected void assertIsVoidReturn(Method method)
78      {
79          assertIsReturn(method,Void.TYPE);
80      }
81  
82      protected void assertUnset(CallableMethod callable, Class<? extends Annotation> annoClass, Method method)
83      {
84          if (callable != null)
85          {
86              // Attempt to add duplicate frame type (a no-no)
87              StringBuilder err = new StringBuilder();
88              err.append("Duplicate @").append(annoClass.getSimpleName()).append(" declaration on ");
89              err.append(method);
90              err.append(System.lineSeparator());
91  
92              err.append("@").append(annoClass.getSimpleName()).append(" previously declared at ");
93              err.append(callable.getMethod());
94  
95              throw new InvalidWebSocketException(err.toString());
96          }
97      }
98  
99      protected void assertValidSignature(Method method, Class<? extends Annotation> annoClass, ParamList validParams)
100     {
101         assertIsPublicNonStatic(method);
102         assertIsReturn(method,Void.TYPE);
103 
104         boolean valid = false;
105 
106         // validate parameters
107         Class<?> actual[] = method.getParameterTypes();
108         for (Class<?>[] params : validParams)
109         {
110             if (isSameParameters(actual,params))
111             {
112                 valid = true;
113                 break;
114             }
115         }
116 
117         if (!valid)
118         {
119             throw InvalidSignatureException.build(method,annoClass,validParams);
120         }
121     }
122 
123     public boolean isAnnotation(Annotation annotation, Class<? extends Annotation> annotationClass)
124     {
125         return annotation.annotationType().equals(annotationClass);
126     }
127 
128     public boolean isSameParameters(Class<?>[] actual, Class<?>[] params)
129     {
130         if (actual.length != params.length)
131         {
132             // skip
133             return false;
134         }
135 
136         int len = params.length;
137         for (int i = 0; i < len; i++)
138         {
139             if (!actual[i].equals(params[i]))
140             {
141                 return false; // not valid
142             }
143         }
144 
145         return true;
146     }
147 
148     protected boolean isSignatureMatch(Method method, ParamList validParams)
149     {
150         assertIsPublicNonStatic(method);
151         assertIsReturn(method,Void.TYPE);
152 
153         // validate parameters
154         Class<?> actual[] = method.getParameterTypes();
155         for (Class<?>[] params : validParams)
156         {
157             if (isSameParameters(actual,params))
158             {
159                 return true;
160             }
161         }
162 
163         return false;
164     }
165 
166     protected boolean isTypeAnnotated(Class<?> pojo, Class<? extends Annotation> expectedAnnotation)
167     {
168         return pojo.getAnnotation(expectedAnnotation) != null;
169     }
170 
171     public abstract void onMethodAnnotation(T metadata, Class<?> pojo, Method method, Annotation annotation);
172 
173     public void scanMethodAnnotations(T metadata, Class<?> pojo)
174     {
175         Class<?> clazz = pojo;
176 
177         while ((clazz != null) && Object.class.isAssignableFrom(clazz))
178         {
179             for (Method method : clazz.getDeclaredMethods())
180             {
181                 Annotation annotations[] = method.getAnnotations();
182                 if ((annotations == null) || (annotations.length <= 0))
183                 {
184                     continue; // skip
185                 }
186                 for (Annotation annotation : annotations)
187                 {
188                     onMethodAnnotation(metadata,clazz,method,annotation);
189                 }
190             }
191 
192             clazz = clazz.getSuperclass();
193         }
194     }
195 }