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

info.novatec.testit.webtester.internal.implementation.advices.EventProducerAdvice Maven / Gradle / Ivy

package info.novatec.testit.webtester.internal.implementation.advices;

import java.lang.reflect.Method;
import java.util.Optional;

import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.StaleElementReferenceException;
import org.openqa.selenium.WebElement;

import lombok.extern.slf4j.Slf4j;
import net.bytebuddy.asm.Advice;

import info.novatec.testit.webtester.browser.Browser;
import info.novatec.testit.webtester.config.Configuration;
import info.novatec.testit.webtester.events.Event;
import info.novatec.testit.webtester.events.EventSystem;
import info.novatec.testit.webtester.events.PageFragmentEventBuilder;
import info.novatec.testit.webtester.events.Produces;
import info.novatec.testit.webtester.internal.implementation.exceptions.NoDefaultConstructorException;
import info.novatec.testit.webtester.pagefragments.PageFragment;


@Slf4j
public class EventProducerAdvice {

    private static final String BUILDER_SUFFIX = "$Builder";

    public static final ThreadLocal THREAD_LOCAL = new ThreadLocal<>();

    @Advice.OnMethodEnter
    public static void onMethodEnter(@Advice.This PageFragment pageFragment, @Advice.Origin Method method) {
        THREAD_LOCAL.remove();
        THREAD_LOCAL.set(new EventProducerImpl(pageFragment, method));
        THREAD_LOCAL.get().onMethodEnter();
    }

    @Advice.OnMethodExit
    public static void onMethodExit(@Advice.This PageFragment pageFragment, @Advice.Origin Method method) {
        try {
            EventProducerImpl impl = THREAD_LOCAL.get();
            if (impl != null) {
                impl.onMethodExit();
            }
        } finally {
            THREAD_LOCAL.remove();

        }
    }

    public static class EventProducerImpl {

        private final PageFragment pageFragment;
        private final Browser browser;
        private final Configuration configuration;
        private final Produces produces;
        private PageFragmentEventBuilder eventBuilder;

        public EventProducerImpl(PageFragment pageFragment, Method method) {
            this.pageFragment = pageFragment;
            this.browser = pageFragment.browser();
            this.configuration = browser.configuration();
            this.produces = method.getAnnotation(Produces.class);
        }

        public void onMethodEnter() {
            if (shouldExecute()) {
                eventBuilder = getEventBuilderFor(produces);
                eventBuilder.setPageFragment(pageFragment);
                if (eventBuilder.needsBeforeData()) {
                    tryToSetBeforeData(eventBuilder, pageFragment);
                }
            }
        }

        public void onMethodExit() {
            if (shouldExecute() && eventBuilder != null) {
                if (eventBuilder.needsAfterData()) {
                    tryToSetAfterData(eventBuilder, pageFragment);
                }
                Event event = eventBuilder.build();
                EventSystem eventSystem = browser.events();
                eventSystem.fireEvent(event);
            }
        }

        private boolean shouldExecute() {
            return configuration.isEventSystemEnabled() && produces != null;
        }

        private PageFragmentEventBuilder getEventBuilderFor(Produces producesEvent) {
            String eventBuilderClassName = producesEvent.value().getName() + BUILDER_SUFFIX;
            Class builderClass = getPageFragmentEventBuilderClass(eventBuilderClassName);
            try {
                return builderClass.newInstance();
            } catch (InstantiationException | IllegalAccessException e) {
                throw new NoDefaultConstructorException(builderClass, e);
            }
        }

        @SuppressWarnings("unchecked")
        private Class getPageFragmentEventBuilderClass(String eventBuilderClassName) {
            return lookupClass(eventBuilderClassName).filter(PageFragmentEventBuilder.class::isAssignableFrom)
                .map(aClass -> ( Class ) aClass)
                .orElseThrow(() -> new IllegalArgumentException("No event builder class found: " + eventBuilderClassName));
        }

        private void tryToSetBeforeData(PageFragmentEventBuilder eventBuilder, PageFragment pageFragment) {
            try {
                WebElement webElement = pageFragment.webElement();
                eventBuilder.setBeforeData(webElement);
            } catch (NoSuchElementException | StaleElementReferenceException e) {
                log.warn("Exception while setting event before data: " + e.getMessage());
                log.debug("Stacktrace for previous warning: ", e);
            }
        }

        private void tryToSetAfterData(PageFragmentEventBuilder eventBuilder, PageFragment pageFragment) {
            try {
                WebElement webElement = pageFragment.webElement();
                eventBuilder.setAfterData(webElement);
            } catch (NoSuchElementException | StaleElementReferenceException e) {
                log.warn("Exception while setting event after data: " + e.getMessage());
                log.debug("Stacktrace for previous warning: ", e);
            }
        }

        private Optional> lookupClass(String className) {
            Class loadedClass = null;
            try {
                loadedClass = Class.forName(className);
            } catch (ClassNotFoundException e) {
                log.error("error loading event builder class: " + className, e);
            }
            return Optional.ofNullable(loadedClass);
        }

    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy