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

info.novatec.testit.webtester.internal.implementation.pagefragments.PageFragmentImplementation Maven / Gradle / Ivy

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

import static net.bytebuddy.matcher.ElementMatchers.isAbstract;
import static net.bytebuddy.matcher.ElementMatchers.isAnnotatedWith;
import static net.bytebuddy.matcher.ElementMatchers.isDefaultMethod;
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;

import java.lang.reflect.InvocationHandler;
import java.util.HashMap;
import java.util.Map;

import net.bytebuddy.ByteBuddy;
import net.bytebuddy.ClassFileVersion;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.dynamic.DynamicType.Builder;
import net.bytebuddy.dynamic.scaffold.subclass.ConstructorStrategy;
import net.bytebuddy.implementation.DefaultMethodCall;
import net.bytebuddy.implementation.InvocationHandlerAdapter;

import info.novatec.testit.webtester.internal.ClasspathUtils;
import info.novatec.testit.webtester.internal.implementation.advices.ActionAdvice;
import info.novatec.testit.webtester.internal.implementation.advices.EventProducerAdvice;
import info.novatec.testit.webtester.internal.implementation.advices.MarkingAdvice;
import info.novatec.testit.webtester.internal.implementation.invocationhandler.AttributeInvocationHandler;
import info.novatec.testit.webtester.internal.implementation.invocationhandler.IdentifyUsingInvocationHandler;
import info.novatec.testit.webtester.internal.implementation.invocationhandler.KotlinDefaultMethodHandler;
import info.novatec.testit.webtester.pagefragments.PageFragment;
import info.novatec.testit.webtester.pagefragments.annotations.Attribute;
import info.novatec.testit.webtester.pagefragments.annotations.IdentifyUsing;


final class PageFragmentImplementation {

    private static final Map, Class>> CACHE =
        new HashMap<>();

    static Class getOrCreate(Class pageFragmentType) {
        ClassLoader classLoader = pageFragmentType.getClassLoader();
        Map, Class> implementationMap =
            CACHE.computeIfAbsent(classLoader, cl -> new HashMap<>());
        return implementationMap.computeIfAbsent(pageFragmentType, PageFragmentImplementation::create);
    }

    private static Class create(Class pageFragmentType) {

        String className = pageFragmentType.getCanonicalName() + "$$Impl";
        ClassLoader classLoader = pageFragmentType.getClassLoader();

        InvocationHandler identifyUsingHandler = new IdentifyUsingInvocationHandler();
        InvocationHandler attributeHandler = new AttributeInvocationHandler();

        Builder pageFragmentTypeBuilder = new ByteBuddy()//
            .with(ClassFileVersion.JAVA_V8)
            .subclass(BasePageFragment.class, ConstructorStrategy.Default.IMITATE_SUPER_CLASS)
            .implement(pageFragmentType)
            .name(className);

        if (ClasspathUtils.KOTLIN_MODULE_LOADED) {
            pageFragmentTypeBuilder = addKotlinImplementations(pageFragmentTypeBuilder, pageFragmentType);
        }

        pageFragmentTypeBuilder = pageFragmentTypeBuilder//
            .method(isDefaultMethod())//
            .intercept(Advice.to(ActionAdvice.class)//
                .wrap(Advice.to(MarkingAdvice.class)//
                    .wrap(Advice.to(EventProducerAdvice.class)//
                        .wrap(DefaultMethodCall.prioritize(pageFragmentType)))));

        pageFragmentTypeBuilder = pageFragmentTypeBuilder//
            .method(isAbstract().and(isAnnotatedWith(IdentifyUsing.class)).and(takesArguments(0)))
            .intercept(InvocationHandlerAdapter.of(identifyUsingHandler));

        pageFragmentTypeBuilder = pageFragmentTypeBuilder//
            .method(isAbstract().and(isAnnotatedWith(Attribute.class)).and(takesArguments(0)))
            .intercept(Advice.to(MarkingAdvice.class)//
                .wrap(InvocationHandlerAdapter.of(attributeHandler)));

        return pageFragmentTypeBuilder.make().load(classLoader).getLoaded();

    }

    private static Builder addKotlinImplementations(Builder pageFragmentTypeBuilder,
        Class pageFragmentType) {
        try {
            Class kotlinPageFragment = Class.forName(ClasspathUtils.KOTLIN_PAGE_FRAGMENT_CLASS);
            if (kotlinPageFragment.isAssignableFrom(pageFragmentType)) {
                InvocationHandler kotlinDefaultMethodHandler = new KotlinDefaultMethodHandler();
                return pageFragmentTypeBuilder//
                    .method(isAbstract())//
                    .intercept(InvocationHandlerAdapter.of(kotlinDefaultMethodHandler));
            }
            return pageFragmentTypeBuilder;
        } catch (ClassNotFoundException e) {
            throw new IllegalStateException("could not load Kotlin PageFragment implementation", e);
        }
    }

    private PageFragmentImplementation() {
        // utility class
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy