gvsig-scripting / org.gvsig.scripting / trunk / org.gvsig.scripting / org.gvsig.scripting.lib / org.gvsig.scripting.lib.impl / src / main / java / org / gvsig / scripting / impl / DefaultScriptingScript.java @ 1084
History | View | Annotate | Download (31 KB)
1 | 164 | jobacas | package org.gvsig.scripting.impl; |
---|---|---|---|
2 | |||
3 | 1023 | jjdelcerro | import groovy.lang.GroovyClassLoader; |
4 | import groovy.util.GroovyScriptEngine; |
||
5 | 164 | jobacas | import java.io.File; |
6 | import java.io.IOException; |
||
7 | 468 | jjdelcerro | import java.io.InputStream; |
8 | 679 | jjdelcerro | import java.io.PrintStream; |
9 | import java.io.Writer; |
||
10 | 1023 | jjdelcerro | import java.net.URL; |
11 | 679 | jjdelcerro | import java.nio.charset.Charset; |
12 | 702 | jjdelcerro | import java.util.ArrayList; |
13 | 1023 | jjdelcerro | import java.util.Arrays; |
14 | 679 | jjdelcerro | import java.util.HashSet; |
15 | 1023 | jjdelcerro | import java.util.LinkedHashSet; |
16 | 301 | jjdelcerro | import java.util.List; |
17 | 679 | jjdelcerro | import java.util.Set; |
18 | 164 | jobacas | |
19 | 301 | jjdelcerro | import javax.script.Compilable; |
20 | import javax.script.CompiledScript; |
||
21 | 164 | jobacas | import javax.script.Invocable; |
22 | import javax.script.ScriptEngine; |
||
23 | import javax.script.ScriptException; |
||
24 | |||
25 | 441 | jjdelcerro | import org.apache.commons.io.FileUtils; |
26 | import org.apache.commons.io.FilenameUtils; |
||
27 | 468 | jjdelcerro | import org.apache.commons.io.IOUtils; |
28 | import org.apache.commons.lang3.StringUtils; |
||
29 | 650 | jjdelcerro | import org.apache.commons.lang3.exception.ExceptionUtils; |
30 | 301 | jjdelcerro | import org.gvsig.scripting.CompileErrorException; |
31 | import org.gvsig.scripting.ExecuteErrorException; |
||
32 | 595 | jjdelcerro | import org.gvsig.scripting.Main; |
33 | 406 | jjdelcerro | import org.gvsig.scripting.ScriptingBaseScript; |
34 | 164 | jobacas | import org.gvsig.scripting.ScriptingFolder; |
35 | import org.gvsig.scripting.ScriptingManager; |
||
36 | import org.gvsig.scripting.ScriptingScript; |
||
37 | 453 | jjdelcerro | import org.gvsig.scripting.ScriptingUnit; |
38 | 391 | vacevedo | import org.gvsig.tools.dispose.Disposable; |
39 | 164 | jobacas | import org.gvsig.tools.observer.Observer; |
40 | import org.gvsig.tools.observer.impl.DelegateWeakReferencingObservable; |
||
41 | 406 | jjdelcerro | import org.gvsig.tools.task.AbstractMonitorableTask; |
42 | 301 | jjdelcerro | import org.ini4j.Ini; |
43 | 1023 | jjdelcerro | import org.python.core.Py; |
44 | 650 | jjdelcerro | import org.python.core.PyException; |
45 | import org.python.core.PyString; |
||
46 | 1023 | jjdelcerro | import org.python.core.PySystemState; |
47 | 650 | jjdelcerro | import org.python.core.PyTraceback; |
48 | 1023 | jjdelcerro | import org.python.core.imp; |
49 | import org.python.jsr223.MyPyScriptEngine; |
||
50 | 441 | jjdelcerro | import org.slf4j.Logger; |
51 | import org.slf4j.LoggerFactory; |
||
52 | 164 | jobacas | |
53 | 1063 | jjdelcerro | @SuppressWarnings("EqualsAndHashcode") |
54 | 301 | jjdelcerro | public class DefaultScriptingScript extends AbstractScript implements |
55 | 468 | jjdelcerro | ScriptingScript { |
56 | 301 | jjdelcerro | |
57 | 1023 | jjdelcerro | @SuppressWarnings("FieldNameHidesFieldInSuperclass") |
58 | 468 | jjdelcerro | private static final Logger logger = LoggerFactory.getLogger(DefaultScriptingScript.class); |
59 | protected String langName; |
||
60 | protected String extension = null; |
||
61 | 669 | jjdelcerro | protected String librarySuffix = null; |
62 | 468 | jjdelcerro | protected ScriptEngine engine = null; |
63 | protected CompiledScript compiledCode;
|
||
64 | 1023 | jjdelcerro | protected boolean useSysPath; |
65 | 301 | jjdelcerro | |
66 | 468 | jjdelcerro | private String code = null; |
67 | private String mainName = "main"; |
||
68 | private final DelegateWeakReferencingObservable delegatedObservable; |
||
69 | 679 | jjdelcerro | private OutputWriter stdout;
|
70 | private OutputWriter stderr;
|
||
71 | 164 | jobacas | |
72 | 679 | jjdelcerro | public static class OutputWriter extends Writer { |
73 | |||
74 | private final Set<Writer> writers = new HashSet<>(); |
||
75 | private final PrintStream out; |
||
76 | |||
77 | private OutputWriter(PrintStream out) { |
||
78 | this.out = out;
|
||
79 | } |
||
80 | |||
81 | @Override
|
||
82 | public void write(char[] cbuf, int off, int len) throws IOException { |
||
83 | try {
|
||
84 | byte[] buf = new String(cbuf).getBytes(Charset.forName("UTF-8")); |
||
85 | out.write(buf, off, len); |
||
86 | } catch (Exception ex) { |
||
87 | logger.warn("Can't output",ex);
|
||
88 | } |
||
89 | for (Writer writer : writers) { |
||
90 | try {
|
||
91 | writer.write(cbuf, off, len); |
||
92 | } catch (Exception ex) { |
||
93 | logger.warn("Can't output",ex);
|
||
94 | } |
||
95 | } |
||
96 | } |
||
97 | |||
98 | @Override
|
||
99 | public void flush() throws IOException { |
||
100 | try {
|
||
101 | out.flush(); |
||
102 | } catch (Exception ex) { |
||
103 | logger.warn("Can't flush",ex);
|
||
104 | } |
||
105 | for (Writer writer : writers) { |
||
106 | try {
|
||
107 | writer.flush(); |
||
108 | } catch (Exception ex) { |
||
109 | logger.warn("Can't flush",ex);
|
||
110 | } |
||
111 | } |
||
112 | } |
||
113 | |||
114 | @Override
|
||
115 | public void close() throws IOException { |
||
116 | } |
||
117 | |||
118 | private void addWriter(Writer out) { |
||
119 | this.writers.add(out);
|
||
120 | } |
||
121 | |||
122 | private void removeWriter(Writer out) { |
||
123 | this.writers.remove(out);
|
||
124 | } |
||
125 | |||
126 | } |
||
127 | |||
128 | 1023 | jjdelcerro | @SuppressWarnings("OverridableMethodCallInConstructor") |
129 | 468 | jjdelcerro | protected DefaultScriptingScript(ScriptingFolder parent, String typename, ScriptingManager manager, String id) { |
130 | super(parent, typename, manager, id);
|
||
131 | 1023 | jjdelcerro | this.useSysPath = false; |
132 | 468 | jjdelcerro | this.setLangName("python"); |
133 | this.setSaved(true); |
||
134 | this.delegatedObservable = new DelegateWeakReferencingObservable(this); |
||
135 | 679 | jjdelcerro | this.stdout = new OutputWriter(System.out); |
136 | this.stderr = new OutputWriter(System.err); |
||
137 | 468 | jjdelcerro | } |
138 | 453 | jjdelcerro | |
139 | 468 | jjdelcerro | public DefaultScriptingScript(ScriptingFolder parent, ScriptingManager manager, String id) { |
140 | this(parent, ScriptingManager.UNIT_SCRIPT, manager, id);
|
||
141 | } |
||
142 | 164 | jobacas | |
143 | 679 | jjdelcerro | @Override
|
144 | 1063 | jjdelcerro | public int hashCode() { |
145 | File f = this.getFile(); |
||
146 | if( f!=null ) { |
||
147 | return "#$FILE$#".hashCode() + f.getAbsolutePath().hashCode(); |
||
148 | } |
||
149 | String s = this.getId(); |
||
150 | if( s != null ) { |
||
151 | return "#$ID$#".hashCode() + s.hashCode(); |
||
152 | } |
||
153 | s = this.getCode();
|
||
154 | if( s != null ) { |
||
155 | return "#$CODE$#".hashCode() + s.hashCode(); |
||
156 | } |
||
157 | return super.hashCode(); |
||
158 | } |
||
159 | @Override
|
||
160 | 679 | jjdelcerro | public void addStdoutWriter(Writer out) { |
161 | this.stdout.addWriter(out);
|
||
162 | } |
||
163 | |||
164 | @Override
|
||
165 | public void addStderrWriter(Writer err) { |
||
166 | this.stderr.addWriter(err);
|
||
167 | } |
||
168 | |||
169 | @Override
|
||
170 | public void removeStdoutWriter(Writer out) { |
||
171 | this.stdout.removeWriter(out);
|
||
172 | } |
||
173 | |||
174 | @Override
|
||
175 | public void removeStderrWriter(Writer err) { |
||
176 | this.stdout.removeWriter(err);
|
||
177 | } |
||
178 | |||
179 | 468 | jjdelcerro | public Object __getattr__(String name) { |
180 | 764 | jjdelcerro | try {
|
181 | 1023 | jjdelcerro | ScriptEngine theEngine = this.getEngine();
|
182 | 764 | jjdelcerro | this.compile();
|
183 | 1023 | jjdelcerro | return theEngine.get(name);
|
184 | 764 | jjdelcerro | } catch(Exception ex) { |
185 | return null; |
||
186 | } |
||
187 | 468 | jjdelcerro | } |
188 | 301 | jjdelcerro | |
189 | 468 | jjdelcerro | public void __setattr__(String name, Object value) { |
190 | 1023 | jjdelcerro | ScriptEngine theEngine = this.getEngine();
|
191 | 468 | jjdelcerro | this.compile();
|
192 | 1023 | jjdelcerro | theEngine.put(name, value); |
193 | 468 | jjdelcerro | } |
194 | 301 | jjdelcerro | |
195 | 468 | jjdelcerro | public Object __call__() { |
196 | return this.run(); |
||
197 | } |
||
198 | 301 | jjdelcerro | |
199 | 468 | jjdelcerro | public Object __call__(Object[] args) { |
200 | return this.run(args); |
||
201 | } |
||
202 | 441 | jjdelcerro | |
203 | 679 | jjdelcerro | public OutputWriter getStdout() {
|
204 | return this.stdout; |
||
205 | } |
||
206 | |||
207 | public OutputWriter getStderr() {
|
||
208 | return this.stderr; |
||
209 | } |
||
210 | |||
211 | 468 | jjdelcerro | protected void notifyErrors(Exception exception, String command) { |
212 | this.delegatedObservable.notifyObservers(new BaseScriptingNotifycation( |
||
213 | this, BaseScriptingNotifycation.RUNTIME_ERROR_NOTIFICATION,
|
||
214 | command, exception)); |
||
215 | } |
||
216 | 164 | jobacas | |
217 | 301 | jjdelcerro | |
218 | 468 | jjdelcerro | @Override
|
219 | public String getCode() { |
||
220 | if (this.code == null) { |
||
221 | File f = null; |
||
222 | try {
|
||
223 | f = this.getFileResource(this.extension); |
||
224 | this.code = FileUtils.readFileToString(f);
|
||
225 | } catch (IOException e) { |
||
226 | String fname = (f == null) ? "(null)" : f.getAbsolutePath(); |
||
227 | logger.warn("Can't load code from file '" + fname + "'."); |
||
228 | } |
||
229 | } |
||
230 | return this.code; |
||
231 | } |
||
232 | 301 | jjdelcerro | |
233 | 468 | jjdelcerro | @Override
|
234 | public void setCode(String code) { |
||
235 | this.code = code;
|
||
236 | this.engine = null; |
||
237 | this.compiledCode = null; |
||
238 | this.setSaved(false); |
||
239 | } |
||
240 | 669 | jjdelcerro | |
241 | @Override
|
||
242 | public String getLibrarySuffix() { |
||
243 | return this.librarySuffix; |
||
244 | } |
||
245 | 301 | jjdelcerro | |
246 | 669 | jjdelcerro | @Override
|
247 | public void setLibrarySuffix(String librarySuffix) { |
||
248 | this.librarySuffix = librarySuffix;
|
||
249 | } |
||
250 | |||
251 | public List<File> getLibFolders() { |
||
252 | List<File> folders = this.manager.getLibFolders(); |
||
253 | String suffix = this.getLibrarySuffix(); |
||
254 | if( suffix == null ) { |
||
255 | return folders;
|
||
256 | } |
||
257 | for( int i=0; i<folders.size(); i++) { |
||
258 | File folder = folders.get(i);
|
||
259 | File f = new File(folder.getParentFile(),folder.getName()+suffix); |
||
260 | if( f.exists() ) {
|
||
261 | folders.set(i, f); |
||
262 | } |
||
263 | } |
||
264 | return folders;
|
||
265 | } |
||
266 | |||
267 | 468 | jjdelcerro | protected String getCodeToInitializeEngine() { |
268 | 1023 | jjdelcerro | String initName = "org/gvsig/scripting/langs/"+this.getLangName().toLowerCase()+"/init.txt"; |
269 | 468 | jjdelcerro | try {
|
270 | 1023 | jjdelcerro | InputStream template = this.getClass().getClassLoader().getResourceAsStream(initName); |
271 | 468 | jjdelcerro | if( template == null ) { |
272 | return null; |
||
273 | } |
||
274 | List<String> lines = IOUtils.readLines(template); |
||
275 | return StringUtils.join(lines, "\n"); |
||
276 | } catch (Exception ex) { |
||
277 | 1023 | jjdelcerro | logger.warn("Can't load code to initialize the script from '"+initName+".",ex); |
278 | 468 | jjdelcerro | return null; |
279 | } |
||
280 | } |
||
281 | 301 | jjdelcerro | |
282 | 1023 | jjdelcerro | private List<URL> getClassPath() { |
283 | Set<URL> classPath = new HashSet<>(); |
||
284 | |||
285 | try {
|
||
286 | // ClassLoader myloader = this.getClass().getClassLoader();
|
||
287 | // if( myloader instanceof URLClassLoader) {
|
||
288 | // classPath.addAll(Arrays.asList(((URLClassLoader) myloader).getURLs()));
|
||
289 | // }
|
||
290 | URL url;
|
||
291 | if( StringUtils.isEmpty(this.getIsolationGroup()) ) { |
||
292 | url = this.getFile().getParentFile().getCanonicalFile().toURI().toURL();
|
||
293 | classPath.add(url); |
||
294 | } |
||
295 | |||
296 | url = this.getManager().getUserFolder().getFile().getCanonicalFile().toURI().toURL();
|
||
297 | classPath.add(url); |
||
298 | |||
299 | List<File> folders = getLibFolders(); |
||
300 | if( folders!=null ) { |
||
301 | for (File folder : folders) { |
||
302 | url = folder.getAbsoluteFile().toURI().toURL(); |
||
303 | classPath.add(url); |
||
304 | } |
||
305 | } |
||
306 | |||
307 | ScriptingFolder folders2 = getManager().getSystemFolder(); |
||
308 | if( folders2!=null ) { |
||
309 | for (ScriptingUnit folder : folders2.getUnits()) {
|
||
310 | url = folder.getFile().getCanonicalFile().toURI().toURL(); |
||
311 | classPath.add(url); |
||
312 | } |
||
313 | } |
||
314 | } catch(Exception ex) { |
||
315 | |||
316 | } |
||
317 | return new ArrayList<>(classPath); |
||
318 | } |
||
319 | |||
320 | private void addClassPathToEngine(ScriptEngine engine, List<URL> classPath) { |
||
321 | if( engine instanceof MyPyScriptEngine ) { |
||
322 | PySystemState sys = Py.getSystemState(); |
||
323 | if( this.useSysPath ) { |
||
324 | // logger.info("Running without sys.classLoader, "+ this.getFile().getAbsolutePath()+".");
|
||
325 | // ReentrantLock importLock =sys.getImportLock();
|
||
326 | // importLock.lock();
|
||
327 | // try {
|
||
328 | 1037 | jjdelcerro | Set<PyString> paths = new LinkedHashSet<>(); |
329 | 1023 | jjdelcerro | for( int i=0; i<sys.path.size(); i++) { |
330 | String path = (String) sys.path.get(i); |
||
331 | 1037 | jjdelcerro | if( !(path.equals("__pyclasspath__/") || path.equals("__classpath__")) ) { |
332 | paths.add(Py.newString(path)); |
||
333 | } |
||
334 | 1023 | jjdelcerro | } |
335 | for (URL url : classPath) { |
||
336 | String path = FileUtils.toFile(url).getAbsolutePath();
|
||
337 | 1037 | jjdelcerro | paths.add(Py.newString(path)); |
338 | 1023 | jjdelcerro | } |
339 | 1037 | jjdelcerro | paths.add(Py.newString("__classpath__"));
|
340 | paths.add(Py.newString("__pyclasspath__/"));
|
||
341 | sys.path.addAll(paths); |
||
342 | |||
343 | 1023 | jjdelcerro | // } finally {
|
344 | // importLock.unlock();
|
||
345 | // }
|
||
346 | } else {
|
||
347 | ClassLoader loader = sys.getClassLoader();
|
||
348 | if( loader == null ) { |
||
349 | ClassLoader parentClassLoader = imp.getParentClassLoader();
|
||
350 | loader = new MutableURLClassLoader(classPath, parentClassLoader);
|
||
351 | sys.setClassLoader(loader); |
||
352 | } else if( loader instanceof MutableURLClassLoader ) { |
||
353 | ((MutableURLClassLoader) loader).addUrls(classPath); |
||
354 | } |
||
355 | } |
||
356 | |||
357 | } else if( engine instanceof GroovyScriptEngine ) { |
||
358 | GroovyClassLoader loader = ((GroovyScriptEngine)engine).getGroovyClassLoader(); |
||
359 | Set<URL> urls = new HashSet(); |
||
360 | urls.addAll(Arrays.asList(loader.getURLs()));
|
||
361 | for (URL url : classPath) { |
||
362 | if( ! urls.contains(url) ) {
|
||
363 | loader.addURL(url); |
||
364 | } |
||
365 | } |
||
366 | } |
||
367 | } |
||
368 | |||
369 | 499 | jjdelcerro | public ScriptEngine getEngine() {
|
370 | 468 | jjdelcerro | if (this.engine == null) { |
371 | 815 | jjdelcerro | synchronized(this.getManager()) { |
372 | ScriptEngine scriptEngine = this.manager.getEngineByLanguage(langName, this.getIsolationGroup()); |
||
373 | 1023 | jjdelcerro | addClassPathToEngine(scriptEngine,getClassPath()); |
374 | |||
375 | 815 | jjdelcerro | scriptEngine.put("script", this); |
376 | scriptEngine.put("Main", Main.class);
|
||
377 | scriptEngine.getContext().setWriter(stdout); |
||
378 | scriptEngine.getContext().setErrorWriter(stderr); |
||
379 | |||
380 | this.engine = scriptEngine;
|
||
381 | 1023 | jjdelcerro | String theCode = this.getCodeToInitializeEngine(); |
382 | if (theCode != null) { |
||
383 | 815 | jjdelcerro | try {
|
384 | 1023 | jjdelcerro | this.engine.eval(theCode);
|
385 | 815 | jjdelcerro | } catch (Exception ex) { |
386 | 1023 | jjdelcerro | logger.warn("Can't initialize engine with the code:\n" + theCode, ex);
|
387 | 815 | jjdelcerro | } |
388 | 468 | jjdelcerro | } |
389 | } |
||
390 | } |
||
391 | return this.engine; |
||
392 | } |
||
393 | 164 | jobacas | |
394 | 468 | jjdelcerro | @Override
|
395 | protected void loadInf(Ini prefs) { |
||
396 | super.loadInf(prefs);
|
||
397 | 164 | jobacas | |
398 | 468 | jjdelcerro | this.setMainName((String) getInfValue(prefs, "Script", "main", "main")); |
399 | 669 | jjdelcerro | this.setLangName((String) getInfValue(prefs, "Script", "Lang",this.getLangName())); |
400 | this.setLibrarySuffix((String) getInfValue(prefs, "Script", "LibraryVersion",null)); |
||
401 | 1023 | jjdelcerro | this.useSysPath = getInfBoolean(prefs, "Script", "useSysPath", false); |
402 | 468 | jjdelcerro | } |
403 | 164 | jobacas | |
404 | 468 | jjdelcerro | @Override
|
405 | public void load(ScriptingFolder folder, String id) { |
||
406 | this.setId(id);
|
||
407 | this.setParent(folder);
|
||
408 | 164 | jobacas | |
409 | 1023 | jjdelcerro | String theExtension = FilenameUtils.getExtension(id);
|
410 | if( theExtension != null ) { |
||
411 | String language = this.manager.getLanguageOfExtension(theExtension); |
||
412 | 468 | jjdelcerro | if( language != null ) { |
413 | this.setLangName(language);
|
||
414 | } |
||
415 | 1023 | jjdelcerro | this.setExtension(theExtension);
|
416 | 468 | jjdelcerro | } |
417 | File f = getFileResource(".inf"); |
||
418 | if (f.isFile()) {
|
||
419 | Ini prefs = null;
|
||
420 | try {
|
||
421 | prefs = new Ini(f);
|
||
422 | } catch (Exception e) { |
||
423 | logger.warn("Can't load 'inf' file '" + f.getAbsolutePath() + "'.", e); |
||
424 | } |
||
425 | loadInf(prefs); |
||
426 | } |
||
427 | 981 | jjdelcerro | this.setCode(null); |
428 | 468 | jjdelcerro | this.setSaved(true); |
429 | } |
||
430 | 301 | jjdelcerro | |
431 | 468 | jjdelcerro | @Override
|
432 | public void save() { |
||
433 | 590 | jjdelcerro | this.saveInfo();
|
434 | // Guardo el codigo en el fichero
|
||
435 | File fcode = this.getFileResource(this.getExtension()); |
||
436 | try {
|
||
437 | FileUtils.write(fcode, this.getCode());
|
||
438 | } catch (Exception e) { |
||
439 | logger.warn("Can't write code to file '" + fcode.getAbsolutePath() + "'.", e); |
||
440 | } |
||
441 | this.setSaved(true); |
||
442 | } |
||
443 | |||
444 | private void saveInfo() { |
||
445 | 468 | jjdelcerro | File f = getFileResource(".inf"); |
446 | if (!f.isFile()) {
|
||
447 | try {
|
||
448 | f.createNewFile(); |
||
449 | } catch (Exception e) { |
||
450 | logger.warn("Can't create 'inf' file '" + f.getAbsolutePath() + "'.", e); |
||
451 | } |
||
452 | } |
||
453 | Ini prefs = null;
|
||
454 | try {
|
||
455 | prefs = new Ini(f);
|
||
456 | } catch (Exception e) { |
||
457 | logger.warn("Can't load 'inf' file '" + f.getAbsolutePath() + "'.", e); |
||
458 | } |
||
459 | save(prefs); |
||
460 | } |
||
461 | 590 | jjdelcerro | |
462 | 468 | jjdelcerro | @Override
|
463 | protected void save(Ini prefs) { |
||
464 | super.save(prefs);
|
||
465 | prefs.put("Script", "main", this.getMainName()); |
||
466 | prefs.put("Script", "Lang", this.getLangName()); |
||
467 | 1023 | jjdelcerro | if( this.useSysPath ) { |
468 | prefs.put("Script", "useSysPath", this.useSysPath); |
||
469 | } |
||
470 | 468 | jjdelcerro | try {
|
471 | prefs.store(); |
||
472 | } catch (IOException e) { |
||
473 | String fname = (prefs.getFile() == null) ? "(null)" : prefs.getFile().getAbsolutePath(); |
||
474 | logger.warn("Can't save inf file (" + fname + ").", e); |
||
475 | } |
||
476 | 164 | jobacas | |
477 | 468 | jjdelcerro | } |
478 | 164 | jobacas | |
479 | 468 | jjdelcerro | @Override
|
480 | public String getLangName() { |
||
481 | return this.langName; |
||
482 | } |
||
483 | 301 | jjdelcerro | |
484 | 468 | jjdelcerro | protected void setLangName(final String langName) { |
485 | if( langName == null ) { |
||
486 | return;
|
||
487 | } |
||
488 | this.langName = langName;
|
||
489 | this.setExtension(this.manager.getExtensionOfLanguage(this.langName)); |
||
490 | } |
||
491 | 164 | jobacas | |
492 | 468 | jjdelcerro | @Override
|
493 | public String[] getIconNames() { |
||
494 | return new String[]{ |
||
495 | 1066 | jjdelcerro | "scripting-icon-" + this.getLangName().toLowerCase(), |
496 | "scripting-icon-" + this.getLangName().toLowerCase() + "-open" |
||
497 | 468 | jjdelcerro | }; |
498 | } |
||
499 | 164 | jobacas | |
500 | 468 | jjdelcerro | @Override
|
501 | public String getMainName() { |
||
502 | return this.mainName; |
||
503 | } |
||
504 | 301 | jjdelcerro | |
505 | 468 | jjdelcerro | @Override
|
506 | public void setMainName(final String mainName) { |
||
507 | this.mainName = mainName;
|
||
508 | } |
||
509 | 702 | jjdelcerro | |
510 | @Override
|
||
511 | public List<File> getFiles() { |
||
512 | List<File> l = new ArrayList<>(); |
||
513 | l.add(this.getScriptFile());
|
||
514 | return l;
|
||
515 | } |
||
516 | 301 | jjdelcerro | |
517 | 468 | jjdelcerro | public String getExtension() { |
518 | return this.extension; |
||
519 | } |
||
520 | 164 | jobacas | |
521 | 468 | jjdelcerro | public void setExtension(final String extension) { |
522 | if (!extension.startsWith(".")) { |
||
523 | this.extension = "." + extension; |
||
524 | } else {
|
||
525 | this.extension = extension;
|
||
526 | } |
||
527 | } |
||
528 | 164 | jobacas | |
529 | 468 | jjdelcerro | @Override
|
530 | public void addObserver(final Observer o) { |
||
531 | this.delegatedObservable.addObserver(o);
|
||
532 | } |
||
533 | 301 | jjdelcerro | |
534 | 468 | jjdelcerro | @Override
|
535 | public void deleteObserver(final Observer o) { |
||
536 | this.delegatedObservable.deleteObserver(o);
|
||
537 | } |
||
538 | 301 | jjdelcerro | |
539 | 468 | jjdelcerro | @Override
|
540 | public void deleteObservers() { |
||
541 | this.delegatedObservable.deleteObservers();
|
||
542 | } |
||
543 | 301 | jjdelcerro | |
544 | 468 | jjdelcerro | @Override
|
545 | public void put(final String name, final Object value) { |
||
546 | this.getEngine().put(name, value);
|
||
547 | } |
||
548 | 301 | jjdelcerro | |
549 | 468 | jjdelcerro | @Override
|
550 | public void compile() { |
||
551 | if (this.compiledCode == null) { |
||
552 | 1023 | jjdelcerro | ScriptEngine theEngine = this.getEngine();
|
553 | if (theEngine instanceof Compilable) { |
||
554 | 468 | jjdelcerro | try {
|
555 | 1023 | jjdelcerro | Compilable compilable = (Compilable) theEngine; |
556 | String theCode = this.getCode(); |
||
557 | 630 | jjdelcerro | if( "python".equalsIgnoreCase(this.getLangName()) ) { |
558 | // If a Unicode string with a coding declaration is passed to compile(),
|
||
559 | // a SyntaxError will be raised, but this is necessary to import from
|
||
560 | // another module, so we remove it.
|
||
561 | // http://bugs.jython.org/issue1696
|
||
562 | 1023 | jjdelcerro | theCode = theCode.replaceFirst("^\\s*#([^:\\n]*)coding:","#$1 c-o-d-i-n-g:"); |
563 | 630 | jjdelcerro | } |
564 | 1023 | jjdelcerro | this.compiledCode = compilable.compile(theCode);
|
565 | if( theEngine instanceof Invocable) { |
||
566 | 595 | jjdelcerro | this.compiledCode.eval();
|
567 | } |
||
568 | 468 | jjdelcerro | } catch (ScriptException e) {
|
569 | 650 | jjdelcerro | Object[] location = this.getLocation(e); |
570 | CompileErrorException ce = new CompileErrorException(
|
||
571 | e.getMessage(), |
||
572 | (File) location[0], |
||
573 | (int) location[1], |
||
574 | (int) location[2], |
||
575 | e |
||
576 | ); |
||
577 | 468 | jjdelcerro | notifyErrors(ce, "compile");
|
578 | throw ce;
|
||
579 | } catch (Throwable e) { |
||
580 | 650 | jjdelcerro | CompileErrorException ce = new CompileErrorException(e.getMessage(), this.getScriptFile(), e); |
581 | 468 | jjdelcerro | notifyErrors(new Exception(e), "compile"); |
582 | throw ce;
|
||
583 | } |
||
584 | } else {
|
||
585 | 1023 | jjdelcerro | String theCode = this.getCode(); |
586 | 468 | jjdelcerro | try {
|
587 | 1023 | jjdelcerro | theEngine.eval(theCode); |
588 | 468 | jjdelcerro | } catch (ScriptException e) {
|
589 | 650 | jjdelcerro | Object[] location = this.getLocation(e); |
590 | CompileErrorException ce = new CompileErrorException(
|
||
591 | e.getMessage(), |
||
592 | (File) location[0], |
||
593 | (int) location[1], |
||
594 | (int) location[2], |
||
595 | e |
||
596 | ); |
||
597 | 468 | jjdelcerro | notifyErrors(ce, "compile");
|
598 | throw ce;
|
||
599 | } |
||
600 | } |
||
601 | } |
||
602 | } |
||
603 | 301 | jjdelcerro | |
604 | 560 | jjdelcerro | public void addDisposable(Disposable disposable) { |
605 | //pass
|
||
606 | } |
||
607 | |||
608 | /**
|
||
609 | * Run the main function of this script.
|
||
610 | * This method is created by familiarity when running the script from another script.
|
||
611 | * @return
|
||
612 | */
|
||
613 | public Object main() { |
||
614 | 468 | jjdelcerro | return this.run(null); |
615 | } |
||
616 | 301 | jjdelcerro | |
617 | 560 | jjdelcerro | /**
|
618 | * Run the main function of this script.
|
||
619 | * This method is created by familiarity when running the script from another script.
|
||
620 | 679 | jjdelcerro | * @param args
|
621 | 560 | jjdelcerro | * @return
|
622 | */
|
||
623 | public Object main(Object... args) { |
||
624 | return this.run(args); |
||
625 | 468 | jjdelcerro | } |
626 | 406 | jjdelcerro | |
627 | 560 | jjdelcerro | |
628 | 679 | jjdelcerro | @Override
|
629 | 560 | jjdelcerro | public Object run() { |
630 | return this.run(null); |
||
631 | } |
||
632 | |||
633 | 468 | jjdelcerro | @Override
|
634 | public Object run(Object args[]) { |
||
635 | 630 | jjdelcerro | if( !this.isEnabled() ) { |
636 | System.err.printf("The script '"+this.getName()+"' is not enabled, see properties page to change.\n"); |
||
637 | return null; |
||
638 | } |
||
639 | 468 | jjdelcerro | if (args == null) { |
640 | args = new Object[]{}; |
||
641 | } |
||
642 | this.compile();
|
||
643 | return this.invokeFunction(this.getMainName(), args); |
||
644 | } |
||
645 | 441 | jjdelcerro | |
646 | 468 | jjdelcerro | @Override
|
647 | public Object invokeFunction(final String name, Object args[]) { |
||
648 | 595 | jjdelcerro | try {
|
649 | if (this.getEngine() instanceof Invocable) { |
||
650 | Invocable invocable = (Invocable) this.getEngine();
|
||
651 | this.compile();
|
||
652 | if (args == null) { |
||
653 | args = new Object[]{}; |
||
654 | } |
||
655 | return invocable.invokeFunction(name, args);
|
||
656 | } else {
|
||
657 | if (this.compiledCode != null) { |
||
658 | Object x = this.compiledCode.eval(); |
||
659 | if( x instanceof Main ) { |
||
660 | return ((Main) x).main(args);
|
||
661 | } else if(x instanceof Runnable) { |
||
662 | ((Runnable) x).run();
|
||
663 | } |
||
664 | } |
||
665 | return null; |
||
666 | 468 | jjdelcerro | } |
667 | 595 | jjdelcerro | } catch (ScriptException e) {
|
668 | 650 | jjdelcerro | Object[] location = this.getLocation(e); |
669 | ExecuteErrorException ee = new ExecuteErrorException(
|
||
670 | e.getMessage(), |
||
671 | (File) location[0], |
||
672 | (int) location[1], |
||
673 | (int) location[2], |
||
674 | e |
||
675 | ); |
||
676 | 595 | jjdelcerro | notifyErrors(ee, "invoke");
|
677 | throw ee;
|
||
678 | 533 | jjdelcerro | |
679 | 595 | jjdelcerro | } catch (Error | Exception e) { |
680 | 650 | jjdelcerro | ExecuteErrorException ee = new ExecuteErrorException(e.getMessage(), this.getScriptFile(), e); |
681 | 595 | jjdelcerro | notifyErrors(ee, "invoke");
|
682 | throw ee;
|
||
683 | 468 | jjdelcerro | } |
684 | } |
||
685 | 415 | jldominguez | |
686 | 468 | jjdelcerro | @Override
|
687 | 650 | jjdelcerro | public File getScriptFile() { |
688 | return this.getFileResource(extension); |
||
689 | } |
||
690 | |||
691 | private Object[] getLocation(ScriptException e) { |
||
692 | Throwable[] es = ExceptionUtils.getThrowables(e); |
||
693 | Exception dbgex; // Para debug con mas comodidad |
||
694 | for( Throwable t : es) { |
||
695 | if( t instanceof PyException ) { |
||
696 | try {
|
||
697 | PyException pyex = (PyException)t; |
||
698 | PyTraceback tb = pyex.traceback; |
||
699 | if( tb!=null ) { |
||
700 | while( tb.tb_next!=null ) { |
||
701 | tb = (PyTraceback) tb.tb_next; |
||
702 | } |
||
703 | String s = tb.tb_frame.f_globals.__getitem__(new PyString("__file__")).asString(); |
||
704 | if( s.endsWith("$py.class") ) { |
||
705 | s = s.substring(0, s.length()-9) + ".py"; |
||
706 | File resource = new File(s); |
||
707 | return new Object[] { resource, tb.tb_lineno, 0}; |
||
708 | } |
||
709 | return new Object[] { this.getScriptFile(), tb.tb_lineno, 0}; |
||
710 | } |
||
711 | } catch(Exception ex) { |
||
712 | // Pass
|
||
713 | dbgex = ex; |
||
714 | } |
||
715 | } |
||
716 | } |
||
717 | int column = e.getColumnNumber();
|
||
718 | if( column < 0 ) { |
||
719 | column = 0;
|
||
720 | } |
||
721 | return new Object[] { this.getScriptFile(), e.getLineNumber(), column }; |
||
722 | } |
||
723 | |||
724 | |||
725 | @Override
|
||
726 | 468 | jjdelcerro | public Object invokeMethod(final Object obj, final String name, Object[] args) |
727 | throws NoSuchMethodException { |
||
728 | 441 | jjdelcerro | |
729 | 468 | jjdelcerro | if (this.getEngine() instanceof Invocable) { |
730 | Invocable invocable = (Invocable) this.getEngine();
|
||
731 | this.compile();
|
||
732 | if (args == null) { |
||
733 | args = new Object[]{}; |
||
734 | } |
||
735 | try {
|
||
736 | return invocable.invokeMethod(obj, name, args);
|
||
737 | } catch (ScriptException e) {
|
||
738 | 650 | jjdelcerro | ExecuteErrorException ee = new ExecuteErrorException(e.getMessage(), this.getScriptFile(), e.getLineNumber(), e.getColumnNumber(), e); |
739 | 468 | jjdelcerro | notifyErrors(ee, "invoke");
|
740 | throw ee;
|
||
741 | } catch (Throwable e) { |
||
742 | 650 | jjdelcerro | ExecuteErrorException ee = new ExecuteErrorException(e.getMessage(), this.getScriptFile(), e); |
743 | 468 | jjdelcerro | notifyErrors(ee, "invoke");
|
744 | throw ee;
|
||
745 | } |
||
746 | } else {
|
||
747 | return null; |
||
748 | } |
||
749 | } |
||
750 | 441 | jjdelcerro | |
751 | 468 | jjdelcerro | @Override
|
752 | public File getResource(String filename) { |
||
753 | return new File(this.getParent().getFile(), filename); |
||
754 | } |
||
755 | 441 | jjdelcerro | |
756 | 468 | jjdelcerro | @Override
|
757 | public String getMimeType() { |
||
758 | return "text/"+ this.getLangName(); |
||
759 | } |
||
760 | 441 | jjdelcerro | |
761 | 679 | jjdelcerro | @Override
|
762 | protected void console_println(String s) { |
||
763 | super.console_println(s);
|
||
764 | try {
|
||
765 | this.stdout.write(s+"\n"); |
||
766 | } catch (IOException ex) { |
||
767 | } |
||
768 | } |
||
769 | |||
770 | 468 | jjdelcerro | class ScriptTask extends AbstractMonitorableTask { |
771 | |||
772 | ScriptingBaseScript script = null;
|
||
773 | Object[] args = null; |
||
774 | |||
775 | protected ScriptTask(ScriptingBaseScript script, Object[] args) { |
||
776 | super(script.getName(), false); |
||
777 | this.args = args;
|
||
778 | this.script = script;
|
||
779 | this.script.put("task", this); |
||
780 | this.script.put("taskStatus", this.getTaskStatus()); |
||
781 | } |
||
782 | |||
783 | @Override
|
||
784 | public void run() { |
||
785 | try {
|
||
786 | console_println("Running script " + this.script.getName() + "."); |
||
787 | script.run(this.args);
|
||
788 | console_println("Script " + this.script.getName() + " terminated."); |
||
789 | } catch (Throwable e) { |
||
790 | console_println("Stript " + this.script.getName() + " aborted."); |
||
791 | } finally {
|
||
792 | this.taskStatus.terminate();
|
||
793 | try {
|
||
794 | Thread.sleep(3000); |
||
795 | } catch (InterruptedException e) { |
||
796 | // Ignore
|
||
797 | } |
||
798 | this.taskStatus.remove();
|
||
799 | } |
||
800 | } |
||
801 | |||
802 | public void showTaskStatus() { |
||
803 | this.taskStatus.add();
|
||
804 | } |
||
805 | } |
||
806 | |||
807 | @Override
|
||
808 | public void runAsTask(Object[] args) { |
||
809 | 630 | jjdelcerro | if( !this.isEnabled() ) { |
810 | System.err.printf("The script '"+this.getName()+"' is not enabled, see properties page to change.\n"); |
||
811 | return;
|
||
812 | } |
||
813 | 468 | jjdelcerro | ScriptTask task = new ScriptTask(this, args); |
814 | task.start(); |
||
815 | } |
||
816 | |||
817 | @Override
|
||
818 | public boolean remove() { |
||
819 | boolean r = true; |
||
820 | File folder = this.getParent().getFile(); |
||
821 | File f = new File(folder, this.getId() + ".inf"); |
||
822 | try {
|
||
823 | FileUtils.forceDelete(f); |
||
824 | } catch (IOException e) { |
||
825 | logger.warn("Can't remove inf file '" + f.getAbsolutePath() + "'.", e); |
||
826 | r = false;
|
||
827 | } |
||
828 | try {
|
||
829 | f = new File(folder, this.getId() + this.getExtension()); |
||
830 | FileUtils.forceDelete(f); |
||
831 | } catch (IOException e) { |
||
832 | logger.warn("Can't remove code file '" + f.getAbsolutePath() + "'.", e); |
||
833 | r = false;
|
||
834 | } |
||
835 | return r;
|
||
836 | } |
||
837 | |||
838 | @Override
|
||
839 | public void create(ScriptingFolder folder, String id, String language) { |
||
840 | this.setParent(folder);
|
||
841 | this.setId(id);
|
||
842 | if (language == null) { |
||
843 | this.setLangName("python"); |
||
844 | } else {
|
||
845 | this.setLangName(language);
|
||
846 | } |
||
847 | this.setExtension(this.manager.getExtensionOfLanguage(getLangName())); |
||
848 | |||
849 | File file = new File(folder.getFile(), id + ".inf"); |
||
850 | try {
|
||
851 | file.createNewFile(); |
||
852 | } catch (IOException e) { |
||
853 | logger.warn("Can't create file of the dialog in '" + file.getAbsolutePath() + "'.", e); |
||
854 | } |
||
855 | 724 | jjdelcerro | File fcode = this.getFileResource(this.getExtension()); |
856 | if( fcode.exists() ) {
|
||
857 | this.saveInfo();
|
||
858 | } else {
|
||
859 | String template = this.getNewTemplate(); |
||
860 | if( template != null ) { |
||
861 | this.setCode(template);
|
||
862 | } |
||
863 | this.save();
|
||
864 | 468 | jjdelcerro | } |
865 | } |
||
866 | |||
867 | public String getNewTemplate() { |
||
868 | 1023 | jjdelcerro | String theTemplateName = "org/gvsig/scripting/langs/"+this.getLangName().toLowerCase()+"/new_template.txt"; |
869 | 468 | jjdelcerro | try {
|
870 | 1023 | jjdelcerro | InputStream template = this.getClass().getClassLoader().getResourceAsStream(theTemplateName); |
871 | 468 | jjdelcerro | if( template == null ) { |
872 | return null; |
||
873 | } |
||
874 | List<String> lines = IOUtils.readLines(template); |
||
875 | return StringUtils.join(lines, "\n"); |
||
876 | } catch (Exception ex) { |
||
877 | 1023 | jjdelcerro | logger.warn("Can't load new-template from '"+theTemplateName+"'.",ex); |
878 | 468 | jjdelcerro | return null; |
879 | } |
||
880 | } |
||
881 | |||
882 | public ScriptingUnit get(String name) { |
||
883 | return this.manager.getScript(name); |
||
884 | } |
||
885 | 560 | jjdelcerro | |
886 | public ScriptingUnit get(File file) { |
||
887 | return this.manager.getScript(file); |
||
888 | } |
||
889 | 590 | jjdelcerro | |
890 | @Override
|
||
891 | public boolean move(ScriptingFolder target) { |
||
892 | if (! manager.validateUnitId(target, this.getId()) ) { |
||
893 | logger.info("Can't move script '"+this.getId()+"' to '"+target.getFile().getAbsolutePath()+"', is not valid."); |
||
894 | return false; |
||
895 | } |
||
896 | if( !this.isSaved() ) { |
||
897 | logger.info("Can't move script '"+this.getId()+"', is not saved."); |
||
898 | return false; |
||
899 | } |
||
900 | try {
|
||
901 | File codefile = this.getFileResource(this.extension); |
||
902 | FileUtils.moveFileToDirectory(this.getFile(), target.getFile(),true); |
||
903 | FileUtils.moveFileToDirectory(codefile, target.getFile(), true);
|
||
904 | this.parent = target;
|
||
905 | this.load(target, id);
|
||
906 | } catch (IOException ex) { |
||
907 | logger.info("Can't move script '"+this.getId()+"' to '"+target.getFile().getAbsolutePath()+"', "+ex.getMessage(),ex); |
||
908 | return false; |
||
909 | } |
||
910 | return true; |
||
911 | } |
||
912 | |||
913 | @Override
|
||
914 | public boolean rename(String newId) { |
||
915 | if (! manager.validateUnitId(this.getParent(), newId) ) { |
||
916 | logger.info("Can't rename script '"+this.getId()+"', target id '"+newId+"' is not valid."); |
||
917 | return false; |
||
918 | } |
||
919 | if( !this.isSaved() ) { |
||
920 | logger.info("Can't rename script '"+this.getId()+"', is not saved."); |
||
921 | return false; |
||
922 | } |
||
923 | try {
|
||
924 | ScriptingFolder target = this.getParent();
|
||
925 | File codefile = this.getFileResource(this.extension); |
||
926 | FileUtils.moveFile(this.getFile(), new File(target.getFile(),newId+".inf") ); |
||
927 | FileUtils.moveFile(codefile, new File(target.getFile(),newId+this.extension)); |
||
928 | this.setId(newId);
|
||
929 | this.saveInfo();
|
||
930 | this.load(target, id);
|
||
931 | } catch (IOException ex) { |
||
932 | logger.info("Can't rename script '"+this.getId()+"' to '"+newId+"', "+ex.getMessage(),ex); |
||
933 | return false; |
||
934 | } |
||
935 | return true; |
||
936 | } |
||
937 | |||
938 | 468 | jjdelcerro | } |