ServletInterceptorFactory.java
package common.http.interceptor;
import java.lang.annotation.Annotation;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
* Questa classe rappresenta un <i>factory</i> per la creazione di oggetti che estendono la classe astratta
* {@link ServletInterceptor}.<br/>
*
* I metodi di questa classe consentono la registrazione di classi ammissibili per l'istanziazione
* e l'istanziazione di questi ultimi.
*
*/
public final class ServletInterceptorFactory {
private ServletInterceptorFactory(){}
private static final
ConcurrentMap<Class<? extends Annotation>, Class<? extends ServletInterceptor<?>>> classes =
new ConcurrentHashMap<>();
/**
* Restituisce un'istanza di {@link ServletInterceptor} associata all'annotazione passata come parametro.<br/>
* La classe concreta dell'oggetto restituito corrisponde a una sottoclasse di {@link ServletInterceptor} registrata
* nella classe factory per mezzo di una previa chiamata al metodo {@link ServletInterceptorFactory#register(Class)}.<br/>
*
* Per poter essere istanziata dal factory, la classe concreta in questione deve possedere un costruttore vuoto pubblico.
*
*
* @param annotation Il tipo di annotazione associato alla classe interceptor da istanziare
* @param <T> Tipo parametrizzato corrispondente al tipo dell'annotazione
* @return Un'istanza di {@link ServletInterceptor} associata all'annotazione passata come parametro
*
* @throws RuntimeException Se la creazione dell'interceptor fallisce
*/
public static <T extends Annotation> ServletInterceptor<T> instantiate(T annotation){
Class<? extends ServletInterceptor<?>> clazz = ServletInterceptorFactory.classes.get(annotation.annotationType());
if(clazz == null)
return null;
ServletInterceptor<T> interceptor;
try {
//noinspection unchecked
interceptor = (ServletInterceptor<T>) clazz.getConstructor().newInstance();
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}
interceptor.init(annotation);
return interceptor;
}
/**
* Registra una sottoclasse di {@link ServletInterceptor} per una seguente istanziazione
*
* @param interceptorClass La classe da registrare
* @throws IllegalArgumentException se si tenta di registrare una classe astratta oppure
* se si tenta di registrare una classe con lo stesso tipo parametrizzato
*/
public static void register(Class<? extends ServletInterceptor<? extends Annotation>> interceptorClass){
if(Modifier.isAbstract(interceptorClass.getModifiers())){
throw new IllegalArgumentException("Interceptor class must be concrete");
}
//get ServletInterceptor.class immediate subclass
Class<?> clazz = interceptorClass;
while(clazz.getSuperclass() != ServletInterceptor.class){
clazz = clazz.getSuperclass();
}
//get ServletInterceptor.class as ParameterizedType object
ParameterizedType genericSuperclass = (ParameterizedType) clazz.getGenericSuperclass();
@SuppressWarnings("unchecked")
Class<? extends Annotation> actualTypeArgument =
(Class<? extends Annotation>) genericSuperclass.getActualTypeArguments()[0];
Class<?> oldValue = classes.putIfAbsent(actualTypeArgument, interceptorClass);
if(oldValue != null){
throw new IllegalArgumentException("There already is a registered Servlet Interceptor with annotation "
+ actualTypeArgument.getName());
}
}
}