Statistics
| Revision:

gvsig-scripting / org.gvsig.scripting / trunk / org.gvsig.scripting / org.gvsig.scripting.lib / org.gvsig.scripting.lib.impl / src / main / java / org / python / jsr223 / MyPyScriptEngine.java @ 1112

History | View | Annotate | Download (9.27 KB)

1
package org.python.jsr223;
2

    
3
import java.lang.reflect.Method;
4
import org.python.core.*;
5
import java.io.Reader;
6
import java.lang.reflect.InvocationHandler;
7
import java.lang.reflect.Proxy;
8
import java.util.List;
9
import javax.script.AbstractScriptEngine;
10
import javax.script.Bindings;
11
import javax.script.Compilable;
12
import javax.script.CompiledScript;
13
import javax.script.Invocable;
14
import javax.script.ScriptContext;
15
import javax.script.ScriptEngine;
16
import javax.script.ScriptEngineFactory;
17
import javax.script.ScriptException;
18
import javax.script.SimpleBindings;
19
import org.python.util.PythonInterpreter;
20

    
21
public class MyPyScriptEngine extends AbstractScriptEngine implements Compilable, Invocable, AutoCloseable {
22

    
23
    //http://stackoverflow.com/questions/29543532/how-to-call-a-function-inside-a-python-script-and-pass-parameters-while-using-sc
24
    private final PythonInterpreter interp;
25
    private final ScriptEngineFactory factory;
26

    
27
    public MyPyScriptEngine(ScriptEngineFactory factory) {
28
        this.factory = factory;
29
        interp = PythonInterpreter.threadLocalStateInterpreter(new PyScriptEngineScope(this, context));
30
    }
31
    
32
    public PythonInterpreter getPythonInterpreter() {
33
        return this.interp;
34
    }
35

    
36
    @Override
37
    public Object eval(String script, ScriptContext context) throws ScriptException {
38
        return eval(compileScript(script, context), context);
39
    }
40

    
41
    private Object eval(PyCode code, ScriptContext context) throws ScriptException {
42
        try {
43
            interp.setIn(context.getReader());
44
            interp.setOut(context.getWriter());
45
            interp.setErr(context.getErrorWriter());
46
            interp.setLocals(new PyScriptEngineScope(this, context));
47
            return interp.eval(code).__tojava__(Object.class);
48
        } catch (PyException pye) {
49
            throw scriptException(pye);
50
        }
51
    }
52

    
53
    @Override
54
    public Object eval(Reader reader, ScriptContext context) throws ScriptException {
55
        return eval(compileScript(reader, context), context);
56
    }
57

    
58
    @Override
59
    public Bindings createBindings() {
60
        return new SimpleBindings();
61
    }
62

    
63
    @Override
64
    public ScriptEngineFactory getFactory() {
65
        return factory;
66
    }
67

    
68
    @Override
69
    public CompiledScript compile(String script) throws ScriptException {
70
        return new PyCompiledScript(compileScript(script, context));
71
    }
72

    
73
    @Override
74
    public CompiledScript compile(Reader reader) throws ScriptException {
75
        return new PyCompiledScript(compileScript(reader, context));
76
    }
77

    
78
    private PyCode compileScript(String script, ScriptContext context) throws ScriptException {
79
        try {
80
            String filename = (String) context.getAttribute(ScriptEngine.FILENAME);
81
            if (filename == null) {
82
                return interp.compile(script);
83
            } else {
84
                return interp.compile(script, filename);
85
            }
86
        } catch (PyException pye) {
87
            throw scriptException(pye);
88
        }
89
    }
90

    
91
    private PyCode compileScript(Reader reader, ScriptContext context) throws ScriptException {
92
        try {
93
            String filename = (String) context.getAttribute(ScriptEngine.FILENAME);
94
            if (filename == null) {
95
                return interp.compile(reader);
96
            } else {
97
                return interp.compile(reader, filename);
98
            }
99
        } catch (PyException pye) {
100
            throw scriptException(pye);
101
        }
102
    }
103

    
104
    @Override
105
    public Object invokeMethod(Object thiz, String name, Object... args) throws ScriptException,
106
            NoSuchMethodException {
107
        try {
108
            interp.setLocals(new PyScriptEngineScope(this, context));
109
            if (!(thiz instanceof PyObject)) {
110
                thiz = Py.java2py(thiz);
111
            }
112
            PyObject method = ((PyObject) thiz).__findattr__(name);
113
            if (method == null) {
114
                throw new NoSuchMethodException(name);
115
            }
116
            //return method.__call__(Py.javas2pys(args)).__tojava__(Object.class);
117
            PyObject result;
118
            if(args != null) {
119
               result = method.__call__(Py.javas2pys(args));
120
            } else {
121
               result = method.__call__();
122
            }
123
            return result.__tojava__(Object.class);
124
        } catch (PyException pye) {
125
            throw scriptException(pye);
126
        }
127
    }
128

    
129
    @Override
130
    public Object invokeFunction(String name, Object... args) throws ScriptException,
131
            NoSuchMethodException {
132
        try {
133
            interp.setIn(context.getReader());
134
            interp.setOut(context.getWriter());
135
            interp.setErr(context.getErrorWriter());
136
            interp.setLocals(new PyScriptEngineScope(this, context));
137
            PyObject function = interp.get(name);
138
            if (function == null) {
139
                throw new NoSuchMethodException(name);
140
            }
141
            PyObject result;
142
            ThreadState state = new ThreadState(this.interp.getSystemState());
143
            if(args != null) {
144
                result = function.__call__(state,Py.javas2pys(args));
145
            } else {
146
                result = function.__call__(state);
147
            }
148
            return result.__tojava__(Object.class);
149
        } catch (PyException pye) {
150
            throw scriptException(pye);
151
        }
152
    }
153

    
154
    @Override
155
    public <T> T getInterface(Class<T> clazz) {
156
        return getInterface(new PyModule("__jsr223__", interp.getLocals()), clazz);
157
    }
158

    
159
    @Override
160
    public <T> T getInterface(Object obj, Class<T> clazz) {
161
        if (obj == null) {
162
            throw new IllegalArgumentException("object expected");
163
        }
164
        if (clazz == null || !clazz.isInterface()) {
165
            throw new IllegalArgumentException("interface expected");
166
        }
167
        interp.setLocals(new PyScriptEngineScope(this, context));
168
        final PyObject thiz = Py.java2py(obj);
169
        @SuppressWarnings("unchecked")
170
        T proxy = (T) Proxy.newProxyInstance(
171
            clazz.getClassLoader(),
172
            new Class[] { clazz },
173
            new InvocationHandler() {
174
                @Override
175
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
176
                    try {
177
                        interp.setLocals(new PyScriptEngineScope(MyPyScriptEngine.this, context));
178
                        PyObject pyMethod = thiz.__findattr__(method.getName());
179
                        if (pyMethod == null)
180
                            throw new NoSuchMethodException(method.getName());
181
                        PyObject result;
182
                        if(args != null) {
183
                            result = pyMethod.__call__(Py.javas2pys(args));
184
                        } else {
185
                            result = pyMethod.__call__();
186
                        }
187
                        return result.__tojava__(Object.class);
188
                    } catch (PyException pye) {
189
                        throw scriptException(pye);
190
                    }
191
                }
192
            });
193
        return proxy;
194
    }
195

    
196
    private static ScriptException scriptException(PyException pye) {
197
        ScriptException se;
198
        try {
199
            pye.normalize();
200

    
201
            PyObject type = pye.type;
202
            PyObject value = pye.value;
203
            PyTraceback tb = pye.traceback;
204

    
205
            if (__builtin__.isinstance(value, Py.SyntaxError)) {
206
                PyObject filename = value.__findattr__("filename");
207
                PyObject lineno = value.__findattr__("lineno");
208
                PyObject offset = value.__findattr__("offset");
209
                value = value.__findattr__("msg");
210

    
211
                se = new ScriptException(
212
                        Py.formatException(type, value),
213
                        filename == null ? "<script>" : filename.toString(),
214
                        lineno == null ? 0 : lineno.asInt(),
215
                        offset == null ? 0 : offset.asInt());
216
            } else if (tb != null) {
217
                String filename;
218
                if (tb.tb_frame == null || tb.tb_frame.f_code == null) {
219
                    filename = null;
220
                } else {
221
                    filename = tb.tb_frame.f_code.co_filename;
222
                }
223
                se = new ScriptException(
224
                        Py.formatException(type, value),
225
                        filename,
226
                        tb.tb_lineno);
227
            } else {
228
                se = new ScriptException(Py.formatException(type, value));
229
            }
230
            se.initCause(pye);
231
            return se;
232
        } catch (Exception ee) {
233
            se = new ScriptException(pye);
234
        }
235
        return se;
236
    }
237

    
238
    private class PyCompiledScript extends CompiledScript {
239
        private final PyCode code;
240

    
241
        PyCompiledScript(PyCode code) {
242
            this.code = code;
243
        }
244

    
245
        @Override
246
        public ScriptEngine getEngine() {
247
            return MyPyScriptEngine.this;
248
        }
249

    
250
        @Override
251
        public Object eval(ScriptContext ctx) throws ScriptException {
252
            return MyPyScriptEngine.this.eval(code, ctx);
253
        }
254
        
255
    }
256

    
257
    @Override
258
    public void close() {
259
        interp.close();
260
    }
261

    
262
    public List<String> getLocalNames() {
263
        PyScriptEngineScope locals = (PyScriptEngineScope) interp.getLocals();
264
        PyList names = (PyList) locals.scope_keys();
265
        return names;
266
    }
267
        
268
}