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 | 679 | jjdelcerro | 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 | 1112 | jjdelcerro | import java.util.List; |
9 | 679 | jjdelcerro | 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 | 1023 | jjdelcerro | |
32 | public PythonInterpreter getPythonInterpreter() {
|
||
33 | return this.interp; |
||
34 | } |
||
35 | 679 | jjdelcerro | |
36 | 1112 | jjdelcerro | @Override
|
37 | 679 | jjdelcerro | 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 | 1112 | jjdelcerro | @Override
|
54 | 679 | jjdelcerro | public Object eval(Reader reader, ScriptContext context) throws ScriptException { |
55 | return eval(compileScript(reader, context), context);
|
||
56 | } |
||
57 | |||
58 | 1112 | jjdelcerro | @Override
|
59 | 679 | jjdelcerro | public Bindings createBindings() {
|
60 | return new SimpleBindings(); |
||
61 | } |
||
62 | |||
63 | 1112 | jjdelcerro | @Override
|
64 | 679 | jjdelcerro | public ScriptEngineFactory getFactory() {
|
65 | return factory;
|
||
66 | } |
||
67 | |||
68 | 1112 | jjdelcerro | @Override
|
69 | 679 | jjdelcerro | public CompiledScript compile(String script) throws ScriptException { |
70 | return new PyCompiledScript(compileScript(script, context)); |
||
71 | } |
||
72 | |||
73 | 1112 | jjdelcerro | @Override
|
74 | 679 | jjdelcerro | 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 | 1112 | jjdelcerro | @Override
|
105 | 679 | jjdelcerro | 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 | 1112 | jjdelcerro | @Override
|
155 | 679 | jjdelcerro | public <T> T getInterface(Class<T> clazz) { |
156 | return getInterface(new PyModule("__jsr223__", interp.getLocals()), clazz); |
||
157 | } |
||
158 | |||
159 | 1112 | jjdelcerro | @Override
|
160 | 679 | jjdelcerro | 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 | 1112 | jjdelcerro | @Override
|
175 | 679 | jjdelcerro | 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 | 1112 | jjdelcerro | ScriptException se; |
198 | 679 | jjdelcerro | 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 | 1112 | jjdelcerro | private final PyCode code; |
240 | 679 | jjdelcerro | |
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 | 1112 | jjdelcerro | |
255 | 679 | jjdelcerro | } |
256 | |||
257 | 1112 | jjdelcerro | @Override
|
258 | 679 | jjdelcerro | public void close() { |
259 | interp.close(); |
||
260 | } |
||
261 | 1112 | jjdelcerro | |
262 | public List<String> getLocalNames() { |
||
263 | PyScriptEngineScope locals = (PyScriptEngineScope) interp.getLocals(); |
||
264 | PyList names = (PyList) locals.scope_keys(); |
||
265 | return names;
|
||
266 | } |
||
267 | |||
268 | 679 | jjdelcerro | } |