package com.maxifier.guice.events; import gnu.trove.map.hash.THashMap; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantReadWriteLock; /** * Created by IntelliJ IDEA. * User: dalex * Date: 22.06.2009 * Time: 17:00:25 */ class EventReflectionParser { private static final Map<Class<? extends Annotation>, HandlerAnnotation> annotationInfos = new THashMap<Class<? extends Annotation>, HandlerAnnotation>(); private static final Map<Class, ListenerClass> classInfos = new THashMap<Class, ListenerClass>(); private static final HandlerAnnotation processing = new HandlerAnnotation(null, null, null); private static final Lock readLock; private static final Lock writeLock; static { ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); readLock = rwl.readLock(); writeLock = rwl.writeLock(); } private EventReflectionParser() { } private static HandlerAnnotation getOrParseAnnotationInfo(Annotation a) throws CyclicFilterAnnotationException { Class<? extends Annotation> ac = a.annotationType(); HandlerAnnotation c = annotationInfos.get(ac); if (c == processing) { throw new CyclicFilterAnnotationException(ac.toString()); } if (c == null) { c = parseAnnotationInfo(ac); annotationInfos.put(ac, c); } return c; } private static HandlerAnnotation parseAnnotationInfo(Class<? extends Annotation> ac) throws CyclicFilterAnnotationException { Filter filter = ac.getAnnotation(Filter.class); if (filter == null) { return new HandlerAnnotation(null, null, null); } annotationInfos.put(ac, processing); List<EventMatcher> matchers = new ArrayList<EventMatcher>(); List<EventClassMatcher> classMatchers = new ArrayList<EventClassMatcher>(); for (Annotation annotation : ac.getAnnotations()) { try { getOrParseAnnotationInfo(annotation).append(annotation, matchers, classMatchers); } catch (CyclicFilterAnnotationException e) { throw new CyclicFilterAnnotationException(ac.toString() + " -> " + e.getMessage()); } } Class<? extends EventMatcher> matcher = filter.matcher(); matcher = matcher == Filter.DefaultMatcher.class ? null : matcher; return new HandlerAnnotation(matchers, classMatchers, matcher); } @SuppressWarnings({"unchecked"}) public static <T> ListenerClass<T> getOrCreateClassInfo(Class<T> c) throws CyclicFilterAnnotationException { ListenerClass<T> ci; readLock.lock(); try { ci = classInfos.get(c); } finally { readLock.unlock(); } if (ci == null) { writeLock.lock(); try { ci = classInfos.get(c); if (ci == null) { List<HandlerMethod<T>> m = new ArrayList<HandlerMethod<T>>(); for (Method method : c.getDeclaredMethods()) { if (isHandlerMethod(method)) { m.add(EventReflectionParser.<T>parseHandlerMethod(method)); } } ci = new ListenerClass<T>(c, m); classInfos.put(c, ci); } } finally { writeLock.unlock(); } } return ci; } private static boolean isHandlerMethod(Method method) { if (!method.isAnnotationPresent(Handler.class)) { return false; } int modifiers = method.getModifiers(); if (Modifier.isStatic(modifiers) || Modifier.isPrivate(modifiers)) { throw new RuntimeException("Handler method should be non-private and non-static, but " + method + " is annotated as handler"); } for (Class<?> exception : method.getExceptionTypes()) { if (!RuntimeException.class.isAssignableFrom(exception)) { throw new RuntimeException("Handler method cannot throw checked exceptions, but " + method + " does (" + exception + ")"); } } return true; } private static <T> HandlerMethod<T> parseHandlerMethod(Method method) throws CyclicFilterAnnotationException { List<EventMatcher> matchers = new ArrayList<EventMatcher>(); List<EventClassMatcher> classMatchers = new ArrayList<EventClassMatcher>(); for (Annotation a : method.getAnnotations()) { getOrParseAnnotationInfo(a).append(a, matchers, classMatchers); } return new HandlerMethod<T>(matchers, classMatchers, new ReflectionHandlerInvocator<Object, T>(method)); // return new HandlerMethod<T>(matchers, classMatchers, new ClassgenHandlerInvocator<Object, T>(method)); } }