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