// package org.lab; 

import jdk.nashorn.api.scripting.AbstractJSObject; 
import jdk.nashorn.api.scripting.JSObject; 
import jdk.nashorn.api.scripting.NashornScriptEngineFactory; 

import javax.script.*; 
import java.util.*; 

public class AbstractJSObjectDemo { 

    public static void main(String[] args) throws ScriptException { 

        ScriptEngine engine = new NashornScriptEngineFactory().getScriptEngine(); 
        Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE); 

        JSObject array = new ArrayLike(new String[] { "red", "green", "blue" }); 
        bindings.put("theArray", array); 

        String script = "print(['first'].concat(theArray));"; 

        engine.eval(script, bindings); 
    } 

    static class ArrayLike extends AbstractJSObject { 

        private final String[] items; 

        ArrayLike(String[] items) { 
            this.items = items; 
        } 

        @Override 
        public Object getMember(String name) { 
            if ("length".equals(name)) return items.length; 
            if ("toString".equals(name)) return ValueAsFunction.forValue(toString()); 
            return null; 
        } 

        @Override 
        public Object getSlot(int index) { 
            return hasSlot(index) ? items[index] : null; 
        } 

        @Override 
        public boolean hasSlot(int slot) { 
            return slot >= 0 && slot < items.length; 
        } 

        @Override 
        public boolean isArray() { 
            return true; 
        } 

        @Override 
        public String toString() { 
            return "ArrayLike{items=" + Arrays.toString(items) + "}"; 
        } 
    } 

    static class ValueAsFunction extends AbstractJSObject { 
        private final Object value; 

        ValueAsFunction(Object value) { 
            this.value = value; 
        } 

        @Override 
        public Object call(Object thiz, Object... args) { 
            return value; 
        } 

        @Override 
        public boolean isFunction() { 
            return true; 
        } 

        static ValueAsFunction forValue(Object value) { 
            return new ValueAsFunction(value); 
        } 
    } 
} 