Statistics
| Revision:

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
}