1 package common.http.interceptor;
2
3 import java.lang.annotation.Annotation;
4 import java.lang.reflect.Modifier;
5 import java.lang.reflect.ParameterizedType;
6 import java.util.concurrent.ConcurrentHashMap;
7 import java.util.concurrent.ConcurrentMap;
8
9 /**
10 * Questa classe rappresenta un <i>factory</i> per la creazione di oggetti che estendono la classe astratta
11 * {@link ServletInterceptor}.<br/>
12 *
13 * I metodi di questa classe consentono la registrazione di classi ammissibili per l'istanziazione
14 * e l'istanziazione di questi ultimi.
15 *
16 */
17 public final class ServletInterceptorFactory {
18 private ServletInterceptorFactory(){}
19
20 private static final
21 ConcurrentMap<Class<? extends Annotation>, Class<? extends ServletInterceptor<?>>> classes =
22 new ConcurrentHashMap<>();
23
24 /**
25 * Restituisce un'istanza di {@link ServletInterceptor} associata all'annotazione passata come parametro.<br/>
26 * La classe concreta dell'oggetto restituito corrisponde a una sottoclasse di {@link ServletInterceptor} registrata
27 * nella classe factory per mezzo di una previa chiamata al metodo {@link ServletInterceptorFactory#register(Class)}.<br/>
28 *
29 * Per poter essere istanziata dal factory, la classe concreta in questione deve possedere un costruttore vuoto pubblico.
30 *
31 *
32 * @param annotation Il tipo di annotazione associato alla classe interceptor da istanziare
33 * @param <T> Tipo parametrizzato corrispondente al tipo dell'annotazione
34 * @return Un'istanza di {@link ServletInterceptor} associata all'annotazione passata come parametro
35 *
36 * @throws RuntimeException Se la creazione dell'interceptor fallisce
37 */
38 public static <T extends Annotation> ServletInterceptor<T> instantiate(T annotation){
39 Class<? extends ServletInterceptor<?>> clazz = ServletInterceptorFactory.classes.get(annotation.annotationType());
40 if(clazz == null)
41 return null;
42
43 ServletInterceptor<T> interceptor;
44 try {
45 //noinspection unchecked
46 interceptor = (ServletInterceptor<T>) clazz.getConstructor().newInstance();
47 } catch (ReflectiveOperationException e) {
48 throw new RuntimeException(e);
49 }
50
51 interceptor.init(annotation);
52 return interceptor;
53 }
54
55 /**
56 * Registra una sottoclasse di {@link ServletInterceptor} per una seguente istanziazione
57 *
58 * @param interceptorClass La classe da registrare
59 * @throws IllegalArgumentException se si tenta di registrare una classe astratta oppure
60 * se si tenta di registrare una classe con lo stesso tipo parametrizzato
61 */
62 public static void register(Class<? extends ServletInterceptor<? extends Annotation>> interceptorClass){
63 if(Modifier.isAbstract(interceptorClass.getModifiers())){
64 throw new IllegalArgumentException("Interceptor class must be concrete");
65 }
66
67 //get ServletInterceptor.class immediate subclass
68 Class<?> clazz = interceptorClass;
69 while(clazz.getSuperclass() != ServletInterceptor.class){
70 clazz = clazz.getSuperclass();
71 }
72 //get ServletInterceptor.class as ParameterizedType object
73 ParameterizedType genericSuperclass = (ParameterizedType) clazz.getGenericSuperclass();
74
75 @SuppressWarnings("unchecked")
76 Class<? extends Annotation> actualTypeArgument =
77 (Class<? extends Annotation>) genericSuperclass.getActualTypeArguments()[0];
78
79 Class<?> oldValue = classes.putIfAbsent(actualTypeArgument, interceptorClass);
80 if(oldValue != null){
81 throw new IllegalArgumentException("There already is a registered Servlet Interceptor with annotation "
82 + actualTypeArgument.getName());
83 }
84 }
85 }