View Javadoc
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  }