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

ch.obermuhlner.scriptengine.java.JavaCompiledScript Maven / Gradle / Ivy

There is a newer version: 2.0.0
Show newest version
package ch.obermuhlner.scriptengine.java;

import ch.obermuhlner.scriptengine.java.execution.ExecutionStrategy;

import javax.script.*;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

/**
 * The compiled Java script created by a {@link JavaScriptEngine}.
 */
public class JavaCompiledScript extends CompiledScript {
    private final JavaScriptEngine engine;
    private final Class compiledClass;
    private final Object compiledInstance;
    private ExecutionStrategy executionStrategy;

    /**
     * Construct a {@link JavaCompiledScript}.
     *
     * @param engine the {@link JavaScriptEngine} that compiled this script
     * @param compiledClass the compiled {@link Class}
     * @param compiledInstance the instance of the compiled {@link Class} or {@code null}
     *                         if no instance was created and only static methods will be called
     *                         by the the {@link ExecutionStrategy}.
     * @param executionStrategy the {@link ExecutionStrategy}
     */
    JavaCompiledScript(JavaScriptEngine engine, Class compiledClass, Object compiledInstance, ExecutionStrategy executionStrategy) {
        this.engine = engine;
        this.compiledClass = compiledClass;
        this.compiledInstance = compiledInstance;
        this.executionStrategy = executionStrategy;
    }

    /**
     * Returns the compiled {@link Class}.
     *
     * @return the compiled {@link Class}.
     */
    public Class getCompiledClass() {
        return compiledClass;
    }

    /**
     * Returns the instance of the compiled {@link Class}.
     *
     * @return the instance of the compiled {@link Class} or {@code null}
     *         if no instance was created and only static methods will be called
     *         by the the {@link ExecutionStrategy}.
     */
    public Object getCompiledInstance() {
        return compiledInstance;
    }

    /**
     * Returns the compiled {@link Class}.
     *
     * @return the compiled {@link Class}.
     * @deprecated in release 1.1.0 this method was deprecated,
     *             use {@link #getCompiledClass()} instead.
     */
    @Deprecated(since = "1.1.0", forRemoval = true)
    public Class getInstanceClass() {
        return getCompiledClass();
    }

    /**
     * Returns the instance of the compiled {@link Class}.
     *
     * @return the instance of the compiled {@link Class} or {@code null}
     *         if no instance was created and only static methods will be called
     *         by the the {@link ExecutionStrategy}.
     * @deprecated in release 1.1.0 this method was deprecated,
     *             use {@link #getCompiledInstance()} instead.
     */
    @Deprecated(since = "1.1.0", forRemoval = true)
    public Object getInstance() {
        return getCompiledInstance();
    }

    /**
     * Sets the {@link ExecutionStrategy} to be used when evaluating the compiled class instance.
     *
     * @param executionStrategy the {@link ExecutionStrategy}
     */
    public void setExecutionStrategy(ExecutionStrategy executionStrategy) {
        this.executionStrategy = executionStrategy;
    }

    @Override
    public ScriptEngine getEngine() {
        return engine;
    }

    @Override
    public Object eval(ScriptContext context) throws ScriptException {
        Bindings globalBindings = context.getBindings(ScriptContext.GLOBAL_SCOPE);
        Bindings engineBindings = context.getBindings(ScriptContext.ENGINE_SCOPE);

        pushVariables(globalBindings, engineBindings);
        Object result = executionStrategy.execute(compiledInstance);
        pullVariables(globalBindings, engineBindings);

        return result;
    }

    private void pushVariables(Bindings globalBindings, Bindings engineBindings) throws ScriptException {
        Map mergedBindings = mergeBindings(globalBindings, engineBindings);

        for (Map.Entry entry : mergedBindings.entrySet()) {
            String name = entry.getKey();
            Object value = entry.getValue();

            try {
                Field field = compiledClass.getField(name);
                field.set(compiledInstance, value);
            } catch (NoSuchFieldException | IllegalAccessException e) {
                throw new ScriptException(e);
            }
        }
    }

    private void pullVariables(Bindings globalBindings, Bindings engineBindings) throws ScriptException {
        for (Field field : compiledClass.getFields()) {
            try {
                String name = field.getName();
                Object value = field.get(compiledInstance);
                setBindingsValue(globalBindings, engineBindings, name, value);
            } catch (IllegalAccessException e) {
                throw new ScriptException(e);
            }
        }
    }

    private void setBindingsValue(Bindings globalBindings, Bindings engineBindings, String name, Object value) {
        if (!engineBindings.containsKey(name) && globalBindings.containsKey(name)) {
            globalBindings.put(name, value);
        } else {
            engineBindings.put(name, value);
        }
    }

    private Map mergeBindings(Bindings... bindingsToMerge) {
        Map variables = new HashMap<>();

        for (Bindings bindings : bindingsToMerge) {
            if (bindings != null) {
                for (Map.Entry globalEntry : bindings.entrySet()) {
                    variables.put(globalEntry.getKey(), globalEntry.getValue());
                }
            }
        }

        return variables;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy