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

ru.yandex.qatools.camelot.common.Metadata Maven / Gradle / Ivy

There is a newer version: 2.5.4
Show newest version
package ru.yandex.qatools.camelot.common;

import ru.yandex.qatools.camelot.api.annotations.AggregationKey;
import ru.yandex.qatools.camelot.api.annotations.Processor;
import ru.yandex.qatools.camelot.api.annotations.Split;
import ru.yandex.qatools.camelot.error.MetadataException;
import ru.yandex.qatools.fsm.annotations.*;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

import static java.util.Arrays.asList;
import static ru.yandex.qatools.fsm.utils.ReflectUtils.collectAllSuperclassesAndInterfaces;
import static ru.yandex.qatools.fsm.utils.ReflectUtils.getMethodsInClassHierarchy;

/**
 * @author Ilya Sadykov
 */
public abstract class Metadata {

    Metadata() {
    }

    private static final Map, MetadataClassInfo> cache = new ConcurrentHashMap<>();

    public static  MetadataClassInfo getMeta(Class clazz, Class metaClass) {
        if (!cache.containsKey(clazz)) {
            try {
                Constructor c = metaClass.getConstructor(Class.class);
                cache.put(clazz, c.newInstance(clazz));
            } catch (Exception e) {
                throw new MetadataException("Failed to instantiate the metadata reader for class " + metaClass, e);
            }
        }
        return cache.get(clazz);
    }

    public static  MetadataClassInfo getMeta(Class clazz) {
        if (!cache.containsKey(clazz)) {
            cache.put(clazz, new ClassInfo<>(clazz));
        }
        return cache.get(clazz);
    }

    @ScanMethodsAnnotatedWith({
            OnException.class, OnTransit.class, BeforeTransit.class,
            AfterTransit.class, Processor.class, AggregationKey.class, Split.class, NewState.class
    })
    public static class ClassInfo implements MetadataClassInfo {
        private final Class clazz;
        private final Map, Method[]> annotatedMethods = new HashMap<>();
        private final Map, Map, Set>> paramTypesMethods = new HashMap<>();
        private final Map superClassesCache = new HashMap<>();
        private final Class[] methodAnnotations = getMethodAnnotations();

        public ClassInfo(Class clazz) {
            this.clazz = clazz;
            buildMethodsCache();
            collectStateSuperClassesCache();
        }

        @Override
        public Method[] getAnnotatedMethods(Class aClass) {
            if (annotatedMethods.containsKey(aClass)) {
                return annotatedMethods.get(aClass);
            }
            return new Method[]{};
        }

        @Override
        public Class[] getSuperClasses(Class clazz) {
            if (superClassesCache.containsKey(clazz)) {
                return superClassesCache.get(clazz);
            }
            final List classes = collectAllSuperclassesAndInterfaces(clazz);
            final Class[] superClasses = classes.toArray(new Class[classes.size()]);
            addCollectedSuperclasses(superClassesCache, superClasses);
            return superClasses;
        }

        @Override
        public Collection getMethodsByParamTypes(Class aClass, Class... paramType) {
            Set result = new HashSet<>();
            if (paramTypesMethods.containsKey(aClass)) {
                Set key = new HashSet<>();
                key.addAll(asList(paramType));
                if (paramTypesMethods.get(aClass).containsKey(key)) {
                    result.addAll(paramTypesMethods.get(aClass).get(key));
                }
            }
            return result;
        }

        private void collectStateSuperClassesCache() {
            for (Class annClass : methodAnnotations) {
                for (Method method : getAnnotatedMethods(annClass)) {
                    for (Class paramClass : method.getParameterTypes()) {
                        addCollectedSuperclasses(superClassesCache, paramClass);
                    }
                }
            }
        }

        private static void addCollectedSuperclasses(Map superclasses, Class... eventClass) {
            for (Class clazz : eventClass) {
                if (!superclasses.containsKey(clazz)) {
                    final List classes = collectAllSuperclassesAndInterfaces(clazz);
                    final Class[] classesArray = classes.toArray(new Class[classes.size()]);
                    superclasses.put(clazz, classesArray);
                    addCollectedSuperclasses(superclasses, classesArray);
                }
            }
        }

        private void buildMethodsCache() {
            for (Class annClass : methodAnnotations) {
                List methods = new ArrayList<>();
                for (Method method : getMethodsInClassHierarchy(clazz)) {
                    if (method.getAnnotation(annClass) != null) {
                        methods.add(method);
                        buildMethodParamsInfoCache(annClass, method);
                    }
                }
                annotatedMethods.put(annClass, methods.toArray(new Method[methods.size()]));
            }
        }

        private void buildMethodParamsInfoCache(Class annClass, Method method) {
            Set paramTypes = new HashSet<>();
            paramTypes.addAll(asList(method.getParameterTypes()));
            if (!paramTypesMethods.containsKey(annClass)) {
                paramTypesMethods.put(annClass, new HashMap, Set>());
            }
            if (!paramTypesMethods.get(annClass).containsKey(paramTypes)) {
                paramTypesMethods.get(annClass).put(paramTypes, new HashSet());
            }
            paramTypesMethods.get(annClass).get(paramTypes).add(method);
        }

        protected Class[] getMethodAnnotations() {
            ScanMethodsAnnotatedWith config = getClass().getAnnotation(ScanMethodsAnnotatedWith.class);
            return config.value();
        }

    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy