All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.unidal.eunit.testfwk.ClassProcessor Maven / Gradle / Ivy

package org.unidal.eunit.testfwk;

import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.unidal.eunit.testfwk.spi.IAnnotationHandler;
import org.unidal.eunit.testfwk.spi.IClassContext;
import org.unidal.eunit.testfwk.spi.IClassProcessor;
import org.unidal.eunit.testfwk.spi.IDeferredAnnotationHandler;
import org.unidal.eunit.testfwk.spi.IDeferredAnnotationHandler.IDeferredHandler;
import org.unidal.eunit.testfwk.spi.IMetaAnnotationHandler;
import org.unidal.eunit.testfwk.spi.Parameter;
import org.unidal.eunit.testfwk.spi.Registry;
import org.unidal.eunit.testfwk.spi.event.Event;
import org.unidal.eunit.testfwk.spi.event.EventType;
import org.unidal.eunit.testfwk.spi.event.IEventListener;

public class ClassProcessor implements IClassProcessor {
   private List m_deferredHandlers = new ArrayList();

   protected void fireEvent(IClassContext ctx, EventType type, AnnotatedElement source) {
      Registry registry = ctx.getRegistry();
      Event event = new Event(type, source);

      for (IEventListener listener : registry.getListeners()) {
         listener.onEvent(ctx, event);
      }
   }

   @Override
   public void process(IClassContext ctx) {
      Registry registry = ctx.getRegistry();
      List> typeHandlers = registry.getAnnotationHandlers(ElementType.TYPE);
      List> metaHandlers = registry.getMetaAnnotationHandlers(ElementType.ANNOTATION_TYPE);
      Class clazz = ctx.getTestClass();

      fireEvent(ctx, EventType.BEFORE_CLASS, clazz);
      processAnnotations(ctx, typeHandlers, metaHandlers, clazz, false);
      processFields(ctx, metaHandlers, Scanner.INSTANCE.getFields(clazz));
      processMethods(ctx, metaHandlers, Scanner.INSTANCE.getMethods(clazz));
      processDeferredHandlers();
      processAnnotations(ctx, typeHandlers, metaHandlers, clazz, true);
      fireEvent(ctx, EventType.AFTER_CLASS, clazz);
   }

   @SuppressWarnings( { "unchecked" })
   protected void processAnnotations(IClassContext ctx, List> handlers,
         List> metaHandlers, AnnotatedElement annotated, boolean after) {
      if (!after) {
         fireEvent(ctx, EventType.BEFORE_ANNOTATIONS, annotated);
      }

      Annotation[] annotations = annotated.getAnnotations();
      Set done = new HashSet();

      if (annotations.length > 0) {
         // Annotation Handlers
         for (IAnnotationHandler handler : handlers) {
            if (handler.isAfter() == after) {
               boolean deferred = (handler instanceof IDeferredAnnotationHandler);
               Class targetAnnotation = handler.getTargetAnnotation();

               for (Annotation annotation : annotations) {
                  if (annotation.annotationType() == targetAnnotation) {
                     if (deferred) {
                        @SuppressWarnings("rawtypes")
                        IDeferredHandler h = ((IDeferredAnnotationHandler) handler).createDeferredHandler(ctx,
                              annotation, annotated);

                        m_deferredHandlers.add(h);
                     } else {
                        ((IAnnotationHandler) handler).handle(ctx, annotation, annotated);
                     }

                     // only first handler get called
                     done.add(annotation);
                     break;
                  }
               }
            }
         }
      }

      if (annotations.length > done.size()) {
         // Meta Annotation Handlers
         for (IMetaAnnotationHandler metaHandler : metaHandlers) {
            Class targetAnnotation = metaHandler.getTargetAnnotation();

            for (Annotation annotation : annotations) {
               if (!done.contains(annotation)) {
                  Annotation meta = annotation.annotationType().getAnnotation(targetAnnotation);

                  if (meta != null) {
                     IMetaAnnotationHandler handler = (IMetaAnnotationHandler) metaHandler;

                     handler.handle(ctx, annotation, meta, annotated, after);
                  }
               }
            }
         }
      }

      if (after) {
         fireEvent(ctx, EventType.AFTER_ANNOTATIONS, annotated);
      }
   }

   protected void processDeferredHandlers() {
      for (IDeferredHandler deferredHandler : m_deferredHandlers) {
         deferredHandler.execute();
      }
   }

   protected void processFields(IClassContext ctx, List> metaHandlers,
         Collection fields) {
      Registry registry = ctx.getRegistry();
      List> fieldHandlers = registry.getAnnotationHandlers(ElementType.FIELD);

      for (Field field : fields) {
         fireEvent(ctx, EventType.BEFORE_FIELD, field);
         processAnnotations(ctx, fieldHandlers, metaHandlers, field, false);
         processAnnotations(ctx, fieldHandlers, metaHandlers, field, true);
         fireEvent(ctx, EventType.AFTER_FIELD, field);
      }
   }

   protected void processMethods(IClassContext ctx, List> metaHandlers,
         Collection methods) {
      Registry registry = ctx.getRegistry();
      List> methodHandlers = registry.getAnnotationHandlers(ElementType.METHOD);
      List> paramHandlers = registry.getAnnotationHandlers(ElementType.PARAMETER);

      for (Method method : methods) {
         fireEvent(ctx, EventType.BEFORE_METHOD, method);
         processAnnotations(ctx, methodHandlers, metaHandlers, method, false);

         Class[] types = method.getParameterTypes();
         Annotation[][] annotations = method.getParameterAnnotations();
         int len = types.length;

         for (int i = 0; i < len; i++) {
            Parameter parameter = new Parameter(method, i, types[i], annotations[i]);

            fireEvent(ctx, EventType.BEFORE_PARAMETER, parameter);
            processAnnotations(ctx, paramHandlers, metaHandlers, parameter, false);
            processAnnotations(ctx, paramHandlers, metaHandlers, parameter, true);
            fireEvent(ctx, EventType.AFTER_PARAMETER, parameter);
         }

         processAnnotations(ctx, methodHandlers, metaHandlers, method, true);
         fireEvent(ctx, EventType.AFTER_METHOD, method);
      }
   }

   public static interface IScanner {
      public Collection getFields(Class clazz);

      public Collection getMethods(Class clazz);
   }

   enum Scanner implements IScanner {
      INSTANCE;

      protected void collectFields(Map result, Class clazz) {
         Field[] fields = clazz.getDeclaredFields();

         for (Field field : fields) {
            String name = field.getName();

            if (!result.containsKey(name)) {
               result.put(name, field);
            }
         }

         Class parent = clazz.getSuperclass();

         if (parent != null && parent != Object.class) {
            collectFields(result, parent);
         }
      }

      protected void collectMethods(Map result, Class clazz) {
         Method[] methods = clazz.getDeclaredMethods();

         for (Method method : methods) {
            String name = method.getName();

            if (!result.containsKey(name)) {
               result.put(name, method);
            }
         }

         Class parent = clazz.getSuperclass();

         if (parent != null && parent != Object.class) {
            collectMethods(result, parent);
         }
      }

      @Override
      public Collection getFields(Class clazz) {
         Map fields = new LinkedHashMap();

         collectFields(fields, clazz);

         return fields.values();
      }

      @Override
      public Collection getMethods(Class clazz) {
         Map methods = new LinkedHashMap();

         collectMethods(methods, clazz);

         return methods.values();
      }
   }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy