Package cuke4duke.internal.jvmclass

Source Code of cuke4duke.internal.jvmclass.ClassLanguage

package cuke4duke.internal.jvmclass;

import cuke4duke.Scenario;
import cuke4duke.StepMother;
import cuke4duke.internal.language.AbstractProgrammingLanguage;
import cuke4duke.internal.language.Transformable;
import cuke4duke.spi.ExceptionFactory;
import cuke4duke.spi.jruby.JRuby;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

public class ClassLanguage extends AbstractProgrammingLanguage {
    private final ObjectFactory objectFactory;
    private final List<ClassAnalyzer> analyzers;
    private final Map<Class<?>, Transformable> transformers = new HashMap<Class<?>, Transformable>();

    public ClassLanguage(ClassLanguageMixin languageMixin, ExceptionFactory exceptionFactory, StepMother stepMother, List<ClassAnalyzer> analyzers) throws Throwable {
        this(languageMixin, exceptionFactory, stepMother, analyzers, createObjectFactory());
    }

    public ClassLanguage(ClassLanguageMixin languageMixin, ExceptionFactory exceptionFactory, StepMother stepMother, List<ClassAnalyzer> analyzers, ObjectFactory objectFactory) throws Throwable {
        super(languageMixin, exceptionFactory);
        this.analyzers = analyzers;
        this.objectFactory = objectFactory;
        objectFactory.addStepMother(stepMother);
        for (ClassAnalyzer analyzer : analyzers) {
            for (Class<?> clazz : analyzer.alwaysLoad()) {
                if (objectFactory.canHandle(clazz)) {
                    objectFactory.addClass(clazz);
                }
            }
        }
    }

    public void addTransform(Class<?> returnType, Transformable javaTransform) {
        transformers.put(returnType, javaTransform);
    }

    @Override
    protected Object customTransform(Object arg, Class<?> parameterType, Locale locale) throws Throwable {
        Transformable transformer = transformers.get(parameterType);
        return transformer == null ? null : transformer.transform(arg, locale);
    }

    @Override
    public void load_code_file(String classFile) throws Throwable {
        Class<?> clazz = loadClass(classFile);
        addClass(clazz);
    }

    public void addClass(Class<?> clazz) {
        if (!Modifier.isAbstract(clazz.getModifiers()) && objectFactory.canHandle(clazz)) {
            objectFactory.addClass(clazz);
        }
    }

    @Override
    public void begin_scenario(Scenario scenario) throws Throwable {
        clearHooksAndStepDefinitions();
        objectFactory.createObjects();
        for (ClassAnalyzer analyzer : analyzers) {
            analyzer.populateStepDefinitionsAndHooks(objectFactory, this);
        }
    }

    @Override
    public void end_scenario() throws Throwable {
        objectFactory.disposeObjects();
    }

    private Class<?> loadClass(String classFile) throws ClassNotFoundException {
        String withoutExt = classFile.substring(0, classFile.length() - ".class".length());
        String[] pathElements = withoutExt.split("\\/");
        String className = null;
        for (int i = pathElements.length - 1; i >= 0; i--) {
            if (className == null) {
                className = pathElements[i];
            } else {
                className = pathElements[i] + "." + className;
            }
            try {
                return JRuby.getRuntime().getJRubyClassLoader().loadClass(className);
            } catch (ClassNotFoundException ignore) {
            }
        }
        throw new ClassNotFoundException("Couldn't determine class from file: " + classFile);
    }

    private static ObjectFactory createObjectFactory() throws Throwable {
        String objectFactoryClassName = System.getProperty("cuke4duke.objectFactory", "cuke4duke.internal.jvmclass.PicoFactory");
        Class<?> ofc = JRuby.getRuntime().getJRubyClassLoader().loadClass(objectFactoryClassName);
        Constructor<?> ctor = ofc.getConstructor();
        try {
            return (ObjectFactory) ctor.newInstance();
        } catch (InvocationTargetException e) {
            throw e.getTargetException();
        }
    }

    public Object invokeHook(Method method, Scenario scenario) throws Throwable {
        Object[] args = new Object[0];
        if (method.getParameterTypes().length == 1) {
            args = new Object[]{scenario};
        } else if (method.getParameterTypes().length > 1) {
            throw cucumberArityMismatchError("Hooks must take 0 or 1 arguments. " + method);
        }
        return invoke(method, args, Locale.getDefault());
    }

    public Object invoke(Method method, Object[] args, Locale locale) throws Throwable {
        Object target = objectFactory.getComponent(method.getDeclaringClass());
        Object[] transformedArgs = transform(args, method.getParameterTypes(), locale);
        return methodInvoker.invoke(method, target, transformedArgs);
    }

    public List<Class<?>> getClasses() {
        return objectFactory.getClasses();
    }
}
TOP

Related Classes of cuke4duke.internal.jvmclass.ClassLanguage

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.