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

info.novatec.testit.livingdoc.reflect.AnnotationLoader Maven / Gradle / Ivy

package info.novatec.testit.livingdoc.reflect;

import static info.novatec.testit.livingdoc.util.LoggerConstants.LOG_ERROR;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;

import org.apache.commons.lang3.StringUtils;
import org.reflections.Reflections;
import org.reflections.scanners.SubTypesScanner;
import org.reflections.scanners.TypeAnnotationsScanner;
import org.reflections.util.ClasspathHelper;
import org.reflections.util.ConfigurationBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import info.novatec.testit.livingdoc.reflect.annotation.FixtureClass;
import info.novatec.testit.livingdoc.util.NameUtils;


/**
 * This Class handles loading of fixture classes via the {@link FixtureClass}
 * annotation.
 * 
 * Get the singleton instance with the static variable {@link #INSTANCE}. The
 * classpath is determined by calling {@link #addLoader(ClassLoader)} where you
 * pass the current {@link ClassLoader}.
 * 
 * Calling the {@link #getAnnotatedFixture(String)} method searches all found
 * annotated fixture classes for a match to the passed {@link String} either by
 * name or by annotation. The match will then be passed to
 * {@link #getClassType(String)} which is responsible for loading the fixture
 * class. In case of more than one match the
 * {@link DuplicateAnnotatedFixturesFoundException} is thrown.
 * 
 * @param  allows us to specify the object return type which can be loaded
 * using {@link #getClassType(String)}
 */
public class AnnotationLoader {
    private static final Logger LOG = LoggerFactory.getLogger(AnnotationLoader.class);

    private ConfigurationBuilder builder;
    private Set> annotatedFixtureClasses = new HashSet>();

    @SuppressWarnings("rawtypes")
    public static AnnotationLoader INSTANCE = new AnnotationLoader();

    public Type getAnnotatedFixture(String name) {

        String fixturename = "(?i)" + NameUtils.toClassName(name) + "(Fixture)?";

        List> matchingAnnotatedClasses = findMatchingAnnotatedFixtures(fixturename);

        List> matchingAliases = null;
        if (matchingAnnotatedClasses.size() != 1) {
            matchingAliases = findFixtureByAlias(name);
        }

        if (matchingAliases != null && matchingAliases.size() == 1) {
            return getClassType(matchingAliases.get(0).getName());
        }
        if (matchingAnnotatedClasses.size() == 1) {
            return getClassType(matchingAnnotatedClasses.get(0).getName());
        }
        if (matchingAnnotatedClasses.size() > 1 || matchingAliases.size() > 1) {
            throw new DuplicateAnnotatedFixturesFoundException(matchingAnnotatedClasses, matchingAliases);
        }
        return null;
    }

    private List> findFixtureByAlias(String alias) {
        List> matchingAliases = new ArrayList>();
        for (Class< ? > annotatedClass : annotatedFixtureClasses) {
            FixtureClass aliasAnnotation = annotatedClass.getAnnotation(FixtureClass.class);
            if (hasAlias(aliasAnnotation, alias)) {
                matchingAliases.add(annotatedClass);
            }
        }
        return matchingAliases;
    }

    private List> findMatchingAnnotatedFixtures(String fixturename) {
        List> matchingAnnotatedClasses = new ArrayList>();
        String discernInnerClass;
        for (Class< ? > in : annotatedFixtureClasses) {
            discernInnerClass = in.toString().substring(StringUtils.indexOf(in.toString(), "$") + 1);
            discernInnerClass = discernInnerClass.substring(StringUtils.lastIndexOf(discernInnerClass, ".") + 1);
            if (Pattern.matches(fixturename, discernInnerClass)) {
                matchingAnnotatedClasses.add(in);
            }
        }
        return matchingAnnotatedClasses;
    }

    public void addLoader(ClassLoader loader) {
        if (builder == null) {
            this.builder = new ConfigurationBuilder();
            builder.setScanners(new SubTypesScanner(), new TypeAnnotationsScanner());
        }
        builder.addClassLoader(loader);
        builder.addUrls(ClasspathHelper.forClassLoader(loader));
        scanClassPath(builder);
    }

    private void scanClassPath(ConfigurationBuilder configBuilder) {
        Reflections reflections = new Reflections(configBuilder);
        annotatedFixtureClasses = reflections.getTypesAnnotatedWith(FixtureClass.class);
    }

    @SuppressWarnings("unchecked")
    private Type getClassType(String name) {
        Class< ? > clazz = loadClass(name, builder);
        return clazz != null ? new Type(( Class< ? extends T> ) clazz) : null;
    }

    private Class< ? > loadClass(String name, ConfigurationBuilder configBuilder) {
        for (ClassLoader classLoader : configBuilder.getClassLoaders()) {
            Class< ? > loadedClass = null;
            try {
                loadedClass = classLoader.loadClass(name);
            } catch (ClassNotFoundException notFound) {
                LOG.trace(LOG_ERROR, notFound);
            } catch (NoClassDefFoundError notFound) {
                LOG.trace(LOG_ERROR, notFound);
            }
            if (loadedClass != null) {
                return loadedClass;
            }
        }
        return null;
    }

    private boolean hasAlias(FixtureClass aliasAnnotation, String alias) {
        if (alias != null) {
            for (String aliasvalue : aliasAnnotation.value()) {
                if (alias.equalsIgnoreCase(aliasvalue)) {
                    return true;
                }
            }
        }
        return false;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy