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

org.fluentlenium.core.inject.FluentInjectHookDefinitionAdder Maven / Gradle / Ivy

package org.fluentlenium.core.inject;

import static org.fluentlenium.core.inject.InjectionAnnotationSupport.isAnnotationTypeHook;
import static org.fluentlenium.core.inject.InjectionAnnotationSupport.isAnnotationTypeHookOptions;

import org.fluentlenium.core.hook.FluentHook;
import org.fluentlenium.core.hook.Hook;
import org.fluentlenium.core.hook.HookControlImpl;
import org.fluentlenium.core.hook.HookDefinition;
import org.fluentlenium.core.hook.HookOptions;
import org.fluentlenium.core.hook.NoHook;
import org.fluentlenium.utils.ReflectionUtils;
import org.apache.commons.lang3.ArrayUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.List;

/**
 * Collects {@link HookDefinition}s based on {@link Hook} and {@link HookOptions} annotations applied on fields and classes.
 */
final class FluentInjectHookDefinitionAdder {

    /**
     * Collects hook definitions in the argument {@code hookDefinitions} based on annotations applied on a class or field.
     *
     * @param annotations     the annotations on a candidate field or class for injection
     * @param hookDefinitions container list for hook definitions to add them to
     */
    void addHookDefinitions(Annotation[] annotations, List> hookDefinitions) {
        Hook currentHookAnnotation = null;
        HookOptions currentHookOptionAnnotation = null;

        Annotation currentAnnotation = null;
        for (Annotation annotation : annotations) {
            applyNoHook(hookDefinitions, annotation);

            Hook hookAnnotation = getHookAnnotation(annotation);
            if (hookAnnotation != null) {
                currentAnnotation = annotation;
                if (currentHookAnnotation != null) {
                    hookDefinitions
                            .add(buildHookDefinition(currentHookAnnotation, currentHookOptionAnnotation, currentAnnotation));
                    currentHookOptionAnnotation = null;
                }
                currentHookAnnotation = hookAnnotation;
            }
            currentHookOptionAnnotation = validateHookOptionsAnnotation(currentHookOptionAnnotation, annotation);
        }

        if (currentHookAnnotation != null) {
            hookDefinitions.add(buildHookDefinition(currentHookAnnotation, currentHookOptionAnnotation, currentAnnotation));
        }
    }

    private HookOptions validateHookOptionsAnnotation(HookOptions currentHookOptionAnnotation, Annotation annotation) {
        HookOptions hookOptionsAnnotation = getHookOptionsAnnotation(annotation);
        if (hookOptionsAnnotation != null) {
            if (currentHookOptionAnnotation != null) {
                throw new FluentInjectException("Unexpected @HookOptions annotation. @Hook is missing.");
            }
            currentHookOptionAnnotation = hookOptionsAnnotation;
        }
        return currentHookOptionAnnotation;
    }

    private Hook getHookAnnotation(Annotation annotation) {
        if (annotation instanceof Hook) {
            return (Hook) annotation;
        } else if (isAnnotationTypeHook(annotation)) {
            return annotation.annotationType().getAnnotation(Hook.class);
        }
        return null;
    }

    private HookOptions getHookOptionsAnnotation(Annotation annotation) {
        if (annotation instanceof HookOptions) {
            return (HookOptions) annotation;
        } else if (isAnnotationTypeHookOptions(annotation)) {
            return annotation.annotationType().getAnnotation(HookOptions.class);
        }
        return null;
    }

    private void applyNoHook(List> hookDefinitions, Annotation annotation) {
        if (annotation instanceof NoHook) {
            Hook[] value = ((NoHook) annotation).value();
            if (ArrayUtils.isEmpty(value)) {
                hookDefinitions.clear();
            } else {
                HookControlImpl
                        .removeHooksFromDefinitions(hookDefinitions, Arrays.stream(value).map(Hook::value).toArray(Class[]::new));
            }
        }
    }

    private  HookDefinition buildHookDefinition(Hook hookAnnotation, HookOptions hookOptionsAnnotation,
                                                      Annotation currentAnnotation) {
        Class hookOptionsClass =
                hookOptionsAnnotation == null ? null : (Class) hookOptionsAnnotation.value();
        T fluentHookOptions = null;
        if (hookOptionsClass != null) {
            try {
                fluentHookOptions = ReflectionUtils.newInstanceOptionalArgs(hookOptionsClass, currentAnnotation);
            } catch (NoSuchMethodException e) {
                throw new FluentInjectException("@HookOption class has no valid constructor", e);
            } catch (IllegalAccessException | InvocationTargetException | InstantiationException e) {
                throw new FluentInjectException("Can't create @HookOption class instance", e);
            }
        }
        Class> hookClass = (Class>) hookAnnotation.value();
        return fluentHookOptions == null ? new HookDefinition<>(hookClass) : new HookDefinition<>(hookClass, fluentHookOptions);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy