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 @ 468
History | View | Annotate | Download (15.8 KB)
1 |
package org.gvsig.scripting.impl; |
---|---|
2 |
|
3 |
import java.io.File; |
4 |
import java.io.IOException; |
5 |
import java.io.InputStream; |
6 |
import java.util.List; |
7 |
|
8 |
import javax.script.Compilable; |
9 |
import javax.script.CompiledScript; |
10 |
import javax.script.Invocable; |
11 |
import javax.script.ScriptEngine; |
12 |
import javax.script.ScriptException; |
13 |
|
14 |
import org.apache.commons.io.FileUtils; |
15 |
import org.apache.commons.io.FilenameUtils; |
16 |
import org.apache.commons.io.IOUtils; |
17 |
import org.apache.commons.lang3.StringUtils; |
18 |
import org.gvsig.scripting.CompileErrorException; |
19 |
import org.gvsig.scripting.ExecuteErrorException; |
20 |
import org.gvsig.scripting.ScriptingBaseScript; |
21 |
import org.gvsig.scripting.ScriptingFolder; |
22 |
import org.gvsig.scripting.ScriptingManager; |
23 |
import org.gvsig.scripting.ScriptingScript; |
24 |
import org.gvsig.scripting.ScriptingUnit; |
25 |
import org.gvsig.tools.dispose.Disposable; |
26 |
import org.gvsig.tools.observer.Observer; |
27 |
import org.gvsig.tools.observer.impl.DelegateWeakReferencingObservable; |
28 |
import org.gvsig.tools.task.AbstractMonitorableTask; |
29 |
import org.ini4j.Ini; |
30 |
import org.slf4j.Logger; |
31 |
import org.slf4j.LoggerFactory; |
32 |
|
33 |
public class DefaultScriptingScript extends AbstractScript implements |
34 |
ScriptingScript { |
35 |
|
36 |
private static final Logger logger = LoggerFactory.getLogger(DefaultScriptingScript.class); |
37 |
protected String langName; |
38 |
protected String extension = null; |
39 |
protected ScriptEngine engine = null; |
40 |
protected CompiledScript compiledCode;
|
41 |
|
42 |
private String code = null; |
43 |
private String mainName = "main"; |
44 |
private boolean saved; |
45 |
private final DelegateWeakReferencingObservable delegatedObservable; |
46 |
|
47 |
protected DefaultScriptingScript(ScriptingFolder parent, String typename, ScriptingManager manager, String id) { |
48 |
super(parent, typename, manager, id);
|
49 |
this.setLangName("python"); |
50 |
this.setSaved(true); |
51 |
this.delegatedObservable = new DelegateWeakReferencingObservable(this); |
52 |
} |
53 |
|
54 |
public DefaultScriptingScript(ScriptingFolder parent, ScriptingManager manager, String id) { |
55 |
this(parent, ScriptingManager.UNIT_SCRIPT, manager, id);
|
56 |
} |
57 |
|
58 |
public Object __getattr__(String name) { |
59 |
ScriptEngine engine = this.getEngine();
|
60 |
this.compile();
|
61 |
return engine.get(name);
|
62 |
} |
63 |
|
64 |
public void __setattr__(String name, Object value) { |
65 |
ScriptEngine engine = this.getEngine();
|
66 |
this.compile();
|
67 |
engine.put(name, value); |
68 |
} |
69 |
|
70 |
public Object __call__() { |
71 |
return this.run(); |
72 |
} |
73 |
|
74 |
public Object __call__(Object[] args) { |
75 |
return this.run(args); |
76 |
} |
77 |
|
78 |
protected void notifyErrors(Exception exception, String command) { |
79 |
this.delegatedObservable.notifyObservers(new BaseScriptingNotifycation( |
80 |
this, BaseScriptingNotifycation.RUNTIME_ERROR_NOTIFICATION,
|
81 |
command, exception)); |
82 |
} |
83 |
|
84 |
@Override
|
85 |
public void setSaved(boolean saved) { |
86 |
this.saved = saved;
|
87 |
} |
88 |
|
89 |
@Override
|
90 |
public String getCode() { |
91 |
if (this.code == null) { |
92 |
File f = null; |
93 |
try {
|
94 |
f = this.getFileResource(this.extension); |
95 |
this.code = FileUtils.readFileToString(f);
|
96 |
} catch (IOException e) { |
97 |
String fname = (f == null) ? "(null)" : f.getAbsolutePath(); |
98 |
logger.warn("Can't load code from file '" + fname + "'."); |
99 |
} |
100 |
} |
101 |
return this.code; |
102 |
} |
103 |
|
104 |
@Override
|
105 |
public void setCode(String code) { |
106 |
this.code = code;
|
107 |
this.engine = null; |
108 |
this.compiledCode = null; |
109 |
this.setSaved(false); |
110 |
} |
111 |
|
112 |
protected String getCodeToInitializeEngine() { |
113 |
String name = "org/gvsig/scripting/langs/"+this.getLangName().toLowerCase()+"/init.txt"; |
114 |
try {
|
115 |
InputStream template = this.getClass().getClassLoader().getResourceAsStream(name); |
116 |
if( template == null ) { |
117 |
return null; |
118 |
} |
119 |
List<String> lines = IOUtils.readLines(template); |
120 |
return StringUtils.join(lines, "\n"); |
121 |
} catch (Exception ex) { |
122 |
logger.warn("Can't load code to initialize the script from '"+name+".",ex); |
123 |
return null; |
124 |
} |
125 |
} |
126 |
|
127 |
protected ScriptEngine getEngine() {
|
128 |
if (this.engine == null) { |
129 |
ScriptEngine scriptEngine = this.manager.getEngineByLanguage(langName);
|
130 |
scriptEngine.put("script", this); |
131 |
this.engine = scriptEngine;
|
132 |
String code = this.getCodeToInitializeEngine(); |
133 |
if (code != null) { |
134 |
try {
|
135 |
this.engine.eval(code);
|
136 |
} catch (Exception ex) { |
137 |
logger.warn("Can't initialize engine with the code:\n" + code, ex);
|
138 |
} |
139 |
} |
140 |
} |
141 |
return this.engine; |
142 |
} |
143 |
|
144 |
@Override
|
145 |
protected void loadInf(Ini prefs) { |
146 |
super.loadInf(prefs);
|
147 |
|
148 |
this.setMainName((String) getInfValue(prefs, "Script", "main", "main")); |
149 |
this.setLangName((String) getInfValue(prefs, "Script", "Lang", |
150 |
this.getLangName()));
|
151 |
} |
152 |
|
153 |
@Override
|
154 |
public void load(ScriptingFolder folder, String id) { |
155 |
this.setId(id);
|
156 |
this.setParent(folder);
|
157 |
|
158 |
String extension = FilenameUtils.getExtension(id);
|
159 |
if( extension != null ) { |
160 |
String language = this.manager.getLanguageOfExtension(extension); |
161 |
if( language != null ) { |
162 |
this.setLangName(language);
|
163 |
} |
164 |
this.setExtension(extension);
|
165 |
} |
166 |
File f = getFileResource(".inf"); |
167 |
if (f.isFile()) {
|
168 |
Ini prefs = null;
|
169 |
try {
|
170 |
prefs = new Ini(f);
|
171 |
} catch (Exception e) { |
172 |
logger.warn("Can't load 'inf' file '" + f.getAbsolutePath() + "'.", e); |
173 |
} |
174 |
loadInf(prefs); |
175 |
} |
176 |
this.setSaved(true); |
177 |
} |
178 |
|
179 |
@Override
|
180 |
public void save() { |
181 |
File f = getFileResource(".inf"); |
182 |
if (!f.isFile()) {
|
183 |
try {
|
184 |
f.createNewFile(); |
185 |
} catch (Exception e) { |
186 |
logger.warn("Can't create 'inf' file '" + f.getAbsolutePath() + "'.", e); |
187 |
} |
188 |
} |
189 |
Ini prefs = null;
|
190 |
try {
|
191 |
prefs = new Ini(f);
|
192 |
} catch (Exception e) { |
193 |
logger.warn("Can't load 'inf' file '" + f.getAbsolutePath() + "'.", e); |
194 |
} |
195 |
save(prefs); |
196 |
// Guardo el codigo en el fichero
|
197 |
File fcode = this.getFileResource(this.getExtension()); |
198 |
try {
|
199 |
FileUtils.write(fcode, this.getCode());
|
200 |
} catch (Exception e) { |
201 |
logger.warn("Can't write code to file '" + fcode.getAbsolutePath() + "'.", e); |
202 |
} |
203 |
this.setSaved(true); |
204 |
} |
205 |
|
206 |
@Override
|
207 |
protected void save(Ini prefs) { |
208 |
super.save(prefs);
|
209 |
prefs.put("Script", "main", this.getMainName()); |
210 |
prefs.put("Script", "Lang", this.getLangName()); |
211 |
try {
|
212 |
prefs.store(); |
213 |
} catch (IOException e) { |
214 |
String fname = (prefs.getFile() == null) ? "(null)" : prefs.getFile().getAbsolutePath(); |
215 |
logger.warn("Can't save inf file (" + fname + ").", e); |
216 |
} |
217 |
|
218 |
} |
219 |
|
220 |
@Override
|
221 |
public String getLangName() { |
222 |
return this.langName; |
223 |
} |
224 |
|
225 |
protected void setLangName(final String langName) { |
226 |
if( langName == null ) { |
227 |
return;
|
228 |
} |
229 |
this.langName = langName;
|
230 |
this.setExtension(this.manager.getExtensionOfLanguage(this.langName)); |
231 |
} |
232 |
|
233 |
@Override
|
234 |
public String[] getIconNames() { |
235 |
return new String[]{ |
236 |
"scripting_" + this.getLangName().toLowerCase(), |
237 |
"scripting_" + this.getLangName().toLowerCase() + "_open" |
238 |
}; |
239 |
} |
240 |
|
241 |
@Override
|
242 |
public String getMainName() { |
243 |
return this.mainName; |
244 |
} |
245 |
|
246 |
@Override
|
247 |
public void setMainName(final String mainName) { |
248 |
this.mainName = mainName;
|
249 |
} |
250 |
|
251 |
public String getExtension() { |
252 |
return this.extension; |
253 |
} |
254 |
|
255 |
public void setExtension(final String extension) { |
256 |
if (!extension.startsWith(".")) { |
257 |
this.extension = "." + extension; |
258 |
} else {
|
259 |
this.extension = extension;
|
260 |
} |
261 |
} |
262 |
|
263 |
@Override
|
264 |
public boolean isSaved() { |
265 |
return this.saved; |
266 |
} |
267 |
|
268 |
@Override
|
269 |
public void addObserver(final Observer o) { |
270 |
this.delegatedObservable.addObserver(o);
|
271 |
} |
272 |
|
273 |
@Override
|
274 |
public void deleteObserver(final Observer o) { |
275 |
this.delegatedObservable.deleteObserver(o);
|
276 |
} |
277 |
|
278 |
@Override
|
279 |
public void deleteObservers() { |
280 |
this.delegatedObservable.deleteObservers();
|
281 |
} |
282 |
|
283 |
@Override
|
284 |
public void put(final String name, final Object value) { |
285 |
this.getEngine().put(name, value);
|
286 |
} |
287 |
|
288 |
@Override
|
289 |
public void compile() { |
290 |
if (this.compiledCode == null) { |
291 |
ScriptEngine engine = this.getEngine();
|
292 |
if (engine instanceof Compilable) { |
293 |
try {
|
294 |
Compilable compilable = (Compilable) engine; |
295 |
this.compiledCode = compilable.compile(this.getCode()); |
296 |
this.compiledCode.eval();
|
297 |
} catch (ScriptException e) {
|
298 |
CompileErrorException ce = new CompileErrorException(e.getMessage(), this.getName(), e.getLineNumber(), e.getColumnNumber(), e); |
299 |
notifyErrors(ce, "compile");
|
300 |
throw ce;
|
301 |
} catch (Throwable e) { |
302 |
CompileErrorException ce = new CompileErrorException(e.getMessage(), this.getName(), e); |
303 |
notifyErrors(new Exception(e), "compile"); |
304 |
throw ce;
|
305 |
} |
306 |
} else {
|
307 |
String preparedCode = this.getCode(); |
308 |
try {
|
309 |
engine.eval(preparedCode); |
310 |
} catch (ScriptException e) {
|
311 |
CompileErrorException ce = new CompileErrorException(e.getMessage(), this.getName(), e.getLineNumber(), e.getColumnNumber(), e); |
312 |
notifyErrors(ce, "compile");
|
313 |
throw ce;
|
314 |
} |
315 |
} |
316 |
} |
317 |
} |
318 |
|
319 |
public Object run() { |
320 |
return this.run(null); |
321 |
} |
322 |
|
323 |
public void addDisposable(Disposable disposable) { |
324 |
//pass
|
325 |
} |
326 |
|
327 |
@Override
|
328 |
public Object run(Object args[]) { |
329 |
if (args == null) { |
330 |
args = new Object[]{}; |
331 |
} |
332 |
this.compile();
|
333 |
return this.invokeFunction(this.getMainName(), args); |
334 |
} |
335 |
|
336 |
@Override
|
337 |
public Object invokeFunction(final String name, Object args[]) { |
338 |
if (this.getEngine() instanceof Invocable) { |
339 |
Invocable invocable = (Invocable) this.getEngine();
|
340 |
this.compile();
|
341 |
if (args == null) { |
342 |
args = new Object[]{}; |
343 |
} |
344 |
try {
|
345 |
return invocable.invokeFunction(name, args);
|
346 |
} catch (ScriptException e) {
|
347 |
ExecuteErrorException ee = new ExecuteErrorException(e.getMessage(), this.getName(), e.getLineNumber(), e.getColumnNumber(), e); |
348 |
notifyErrors(ee, "invoke");
|
349 |
throw ee;
|
350 |
} catch (Throwable e) { |
351 |
ExecuteErrorException ee = new ExecuteErrorException(e.getMessage(), this.getName(), e); |
352 |
notifyErrors(ee, "invoke");
|
353 |
throw ee;
|
354 |
} |
355 |
} else {
|
356 |
return null; |
357 |
} |
358 |
} |
359 |
|
360 |
@Override
|
361 |
public Object invokeMethod(final Object obj, final String name, Object[] args) |
362 |
throws NoSuchMethodException { |
363 |
|
364 |
if (this.getEngine() instanceof Invocable) { |
365 |
Invocable invocable = (Invocable) this.getEngine();
|
366 |
this.compile();
|
367 |
if (args == null) { |
368 |
args = new Object[]{}; |
369 |
} |
370 |
try {
|
371 |
return invocable.invokeMethod(obj, name, args);
|
372 |
} catch (ScriptException e) {
|
373 |
ExecuteErrorException ee = new ExecuteErrorException(e.getMessage(), this.getName(), e.getLineNumber(), e.getColumnNumber(), e); |
374 |
notifyErrors(ee, "invoke");
|
375 |
throw ee;
|
376 |
} catch (Throwable e) { |
377 |
ExecuteErrorException ee = new ExecuteErrorException(e.getMessage(), this.getName(), e); |
378 |
notifyErrors(ee, "invoke");
|
379 |
throw ee;
|
380 |
} |
381 |
} else {
|
382 |
return null; |
383 |
} |
384 |
} |
385 |
|
386 |
@Override
|
387 |
public File getResource(String filename) { |
388 |
return new File(this.getParent().getFile(), filename); |
389 |
} |
390 |
|
391 |
@Override
|
392 |
public String getMimeType() { |
393 |
return "text/"+ this.getLangName(); |
394 |
} |
395 |
|
396 |
class ScriptTask extends AbstractMonitorableTask { |
397 |
|
398 |
ScriptingBaseScript script = null;
|
399 |
Object[] args = null; |
400 |
|
401 |
protected ScriptTask(ScriptingBaseScript script, Object[] args) { |
402 |
super(script.getName(), false); |
403 |
this.args = args;
|
404 |
this.script = script;
|
405 |
this.script.put("task", this); |
406 |
this.script.put("taskStatus", this.getTaskStatus()); |
407 |
} |
408 |
|
409 |
@Override
|
410 |
public void run() { |
411 |
try {
|
412 |
console_println("Running script " + this.script.getName() + "."); |
413 |
script.run(this.args);
|
414 |
console_println("Script " + this.script.getName() + " terminated."); |
415 |
} catch (Throwable e) { |
416 |
console_println("Stript " + this.script.getName() + " aborted."); |
417 |
} finally {
|
418 |
this.taskStatus.terminate();
|
419 |
try {
|
420 |
Thread.sleep(3000); |
421 |
} catch (InterruptedException e) { |
422 |
// Ignore
|
423 |
} |
424 |
this.taskStatus.remove();
|
425 |
} |
426 |
} |
427 |
|
428 |
public void showTaskStatus() { |
429 |
this.taskStatus.add();
|
430 |
} |
431 |
} |
432 |
|
433 |
@Override
|
434 |
public void runAsTask(Object[] args) { |
435 |
ScriptTask task = new ScriptTask(this, args); |
436 |
task.start(); |
437 |
} |
438 |
|
439 |
@Override
|
440 |
public boolean remove() { |
441 |
boolean r = true; |
442 |
File folder = this.getParent().getFile(); |
443 |
File f = new File(folder, this.getId() + ".inf"); |
444 |
try {
|
445 |
FileUtils.forceDelete(f); |
446 |
} catch (IOException e) { |
447 |
logger.warn("Can't remove inf file '" + f.getAbsolutePath() + "'.", e); |
448 |
r = false;
|
449 |
} |
450 |
try {
|
451 |
f = new File(folder, this.getId() + this.getExtension()); |
452 |
FileUtils.forceDelete(f); |
453 |
} catch (IOException e) { |
454 |
logger.warn("Can't remove code file '" + f.getAbsolutePath() + "'.", e); |
455 |
r = false;
|
456 |
} |
457 |
return r;
|
458 |
} |
459 |
|
460 |
@Override
|
461 |
public void create(ScriptingFolder folder, String id, String language) { |
462 |
this.setParent(folder);
|
463 |
this.setId(id);
|
464 |
if (language == null) { |
465 |
this.setLangName("python"); |
466 |
} else {
|
467 |
this.setLangName(language);
|
468 |
} |
469 |
this.setExtension(this.manager.getExtensionOfLanguage(getLangName())); |
470 |
|
471 |
File file = new File(folder.getFile(), id + ".inf"); |
472 |
try {
|
473 |
file.createNewFile(); |
474 |
} catch (IOException e) { |
475 |
logger.warn("Can't create file of the dialog in '" + file.getAbsolutePath() + "'.", e); |
476 |
} |
477 |
String template = this.getNewTemplate(); |
478 |
if( template != null ) { |
479 |
this.setCode(template);
|
480 |
} |
481 |
this.save();
|
482 |
} |
483 |
|
484 |
public String getNewTemplate() { |
485 |
String name = "org/gvsig/scripting/langs/"+this.getLangName().toLowerCase()+"/new_template.txt"; |
486 |
try {
|
487 |
InputStream template = this.getClass().getClassLoader().getResourceAsStream(name); |
488 |
if( template == null ) { |
489 |
return null; |
490 |
} |
491 |
List<String> lines = IOUtils.readLines(template); |
492 |
return StringUtils.join(lines, "\n"); |
493 |
} catch (Exception ex) { |
494 |
logger.warn("Can't load new-template from '"+name+"'.",ex); |
495 |
return null; |
496 |
} |
497 |
} |
498 |
|
499 |
public ScriptingUnit get(String name) { |
500 |
return this.manager.getScript(name); |
501 |
} |
502 |
} |