/* * codjo.net * * Common Apache License 2.0 */ package net.codjo.dataprocess.common.eventsbinder; import net.codjo.dataprocess.common.eventsbinder.annotations.BindAnnotation; import net.codjo.dataprocess.common.eventsbinder.annotations.OnError; import net.codjo.dataprocess.common.eventsbinder.dynalistener.DynamicListener; import net.codjo.dataprocess.common.eventsbinder.reflect.GetterHelper; import net.codjo.dataprocess.common.eventsbinder.reflect.GetterHelperException; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.EventListener; import java.util.HashMap; import java.util.Map; import org.apache.log4j.Logger; /** * This utility class is used to bind a logic to an object */ public class EventsBinder { private static final Logger LOG = Logger.getLogger(EventsBinder.class); private final Map<Class<?extends Annotation>, AnnotationManager<?extends Annotation>> annotationsManagers = new HashMap<Class<?extends Annotation>, AnnotationManager<?extends Annotation>>(); public void registerAnnotationManager(Class<Annotation> clazz, AnnotationManager<?extends Annotation> annotationManager) { annotationsManagers.put(clazz, annotationManager); } protected AnnotationManager getAnnotationManagerFor(Annotation annotation) { return annotationsManagers.get(annotation.annotationType()); } /** * Effectiv bind a logic class with another object * * @param logic * @param boundObject * * @throws EventBinderException */ public void bind(Object logic, Object boundObject) throws EventBinderException { Method errorMethod = getErrorMethod(logic); for (Method currentMethod : logic.getClass().getMethods()) { for (Annotation annotationBasic : currentMethod.getAnnotations()) { boolean isABindAnnotation = annotationBasic.annotationType().getAnnotation(BindAnnotation.class) != null; if (isABindAnnotation) { try { bindOneAnnotation(annotationBasic, logic, currentMethod, errorMethod, boundObject); } catch (Exception ex) { throw new EventBinderException(ex); } } } } } protected Method getErrorMethod(Object logic) throws EventBinderException { Method errorMethod = null; for (Method currentMethod : logic.getClass().getMethods()) { if (currentMethod.isAnnotationPresent(OnError.class)) { if (errorMethod != null) { throw new EventBinderException("Two method are tagged with @OnError in the logic (" + logic.getClass() + ")"); } if (currentMethod.getParameterTypes().length != 1 || currentMethod.getParameterTypes()[0] != Throwable.class) { throw new EventBinderException( "The method tagged with @OnError in the logic must have ONE Throwable parameter (" + logic.getClass() + ")"); } errorMethod = currentMethod; } } if (errorMethod == null) { throw new EventBinderException("There's no method tagged with @OnError in the logic (" + logic.getClass() + ")"); } return errorMethod; } protected void bindOneAnnotation(Annotation currentAnnotation, Object logic, Method currentMethod, Method erroMethod, Object boundObject) throws IllegalAccessException, InstantiationException, EventBinderException, GetterHelperException { AnnotationManager annotationManager; annotationManager = annotationsManagers.get(currentAnnotation.annotationType()); if (annotationManager == null) { mountAnnotationManager(currentAnnotation); annotationManager = annotationsManagers.get(currentAnnotation.annotationType()); } MethodCallEventReaction methodCallReaction = new MethodCallEventReaction(logic, currentMethod, erroMethod, boundObject); String[] propertyNames = annotationManager.getBoundPropertiesNames(currentAnnotation); bindOneAnnotationToAllProperties(propertyNames, boundObject, annotationManager, currentAnnotation, methodCallReaction); } protected void bindOneAnnotationToAllProperties(String[] propertyNames, Object boundObject, AnnotationManager annotationManager, Annotation currentAnnotation, MethodCallEventReaction methodCallReaction) throws GetterHelperException, EventBinderException { for (String propertyName : propertyNames) { Object property = GetterHelper.getProperty(propertyName, boundObject); Class<?extends EventListener> listenerClass = annotationManager.getListenerClass(currentAnnotation); EventListener listener = DynamicListener.createEventListener(listenerClass, methodCallReaction, annotationManager.createEventChecker(currentAnnotation)); annotationManager.registerListener(currentAnnotation, property, listener, listenerClass); } } protected void mountAnnotationManager(Annotation currentAnnotation) throws IllegalAccessException, InstantiationException, EventBinderException { BindAnnotation bindAnnotation = currentAnnotation.annotationType().getAnnotation(BindAnnotation.class); if (bindAnnotation == null) { throw new EventBinderException(EventBinderException.printNotABindAnnotation(currentAnnotation)); } Class<?extends AnnotationManager<?extends Annotation>> annotationManagerClass = bindAnnotation.managerClass(); LOG.debug("Mount " + annotationManagerClass); annotationsManagers.put(currentAnnotation.annotationType(), annotationManagerClass.newInstance()); } }