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 @ 453

History | View | Annotate | Download (12.5 KB)

1
package org.gvsig.scripting.impl;
2

    
3
import java.io.File;
4
import java.io.IOException;
5
import java.util.List;
6
import java.util.Map;
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.gvsig.scripting.CompileErrorException;
17
import org.gvsig.scripting.ExecuteErrorException;
18
import org.gvsig.scripting.ScriptingBaseScript;
19
import org.gvsig.scripting.ScriptingFolder;
20
import org.gvsig.scripting.ScriptingManager;
21
import org.gvsig.scripting.ScriptingScript;
22
import org.gvsig.scripting.ScriptingUnit;
23
import org.gvsig.tools.dispose.Disposable;
24
import org.gvsig.tools.observer.Observer;
25
import org.gvsig.tools.observer.impl.DelegateWeakReferencingObservable;
26
import org.gvsig.tools.task.AbstractMonitorableTask;
27
import org.ini4j.Ini;
28
import org.slf4j.Logger;
29
import org.slf4j.LoggerFactory;
30

    
31
public class DefaultScriptingScript extends AbstractScript implements
32
                ScriptingScript {
33
        
34
        private static final Logger logger = LoggerFactory.getLogger(DefaultScriptingScript.class);
35
        protected String langName;
36
        protected String extension = null;
37
        protected ScriptEngine engine = null;
38
        protected CompiledScript compiledCode;
39

    
40
        private String code = null;
41
        private String mainName = "main";
42
        private boolean saved;
43
        private final DelegateWeakReferencingObservable delegatedObservable;
44

    
45
        protected DefaultScriptingScript(ScriptingFolder parent, String typename, ScriptingManager manager, String id) {
46
                super(parent, typename, manager, id);
47
                this.setLangName("python");
48
                this.setSaved(true);
49
                this.delegatedObservable = new DelegateWeakReferencingObservable(this);
50
        }
51
        
52
        public DefaultScriptingScript(ScriptingFolder parent, ScriptingManager manager, String id) {
53
                this(parent, ScriptingManager.UNIT_SCRIPT, manager, id);
54
        }
55
        
56
        public ScriptingUnit load(String name) {
57
                ScriptingUnit script = null;
58
                File f = null;
59
                String scname = name;
60
                if (!scname.endsWith(".inf")) {
61
                        scname = scname + ".inf";
62
                }
63
                if (scname.startsWith("/")) {
64
                        f = new File(scname.substring(1));
65
                } else {
66
                        f = new File(this.getParent().getFile(), scname);
67
                        if (!f.exists()) {
68
                                return null;
69
                        }
70
                }
71
                try {
72
                        script = this.getManager().getScript(f);
73
                } catch (ScriptNotFoundException ex) {
74
                        return null;
75
                }
76
                if (script != null) {
77
                        this.getEngine().put(script.getId(), script);
78
                }
79
                return script;
80
        }
81

    
82
        public Object __getattr__(String name) {
83
                ScriptEngine engine = this.getEngine();
84
                this.compile();
85
                return engine.get(name);
86
        }
87

    
88
        public void __setattr__(String name, Object value) {
89
                ScriptEngine engine = this.getEngine();
90
                this.compile();
91
                engine.put(name,value);
92
        }
93
        
94
        public Object __call__() {
95
                return this.run();
96
        }
97
        
98
        public Object __call__(Object[] args) {
99
                return this.run(args);
100
        }
101
        
102
        protected void notifyErrors(Exception exception, String command) {
103
                this.delegatedObservable.notifyObservers(new BaseScriptingNotifycation(
104
                                this, BaseScriptingNotifycation.RUNTIME_ERROR_NOTIFICATION,
105
                                command, exception));
106
        }
107

    
108
        public void setSaved(boolean saved) {
109
                this.saved = saved;
110
        }
111

    
112
        public String getCode() {
113
                if (this.code == null) {
114
                        File f=null;
115
                        try {
116
                                f = this.getFileResource(this.extension);
117
                                this.code = FileUtils.readFileToString(f);
118
                        } catch (IOException e) {
119
                                String fname = (f==null)? "(null)":f.getAbsolutePath();
120
                                logger.warn("Can't load code from file '"+fname+"'.");
121
                        }
122
                }
123
                return this.code;
124
        }
125

    
126
        public void setCode(String code) {
127
                this.code = code;
128
                this.engine = null;
129
                this.compiledCode = null;
130
                this.setSaved(false);
131
        }
132

    
133
        private String getPreparedCode() {
134
                return this.getCode();
135
        }
136

    
137
        protected String getCodeToInitializeEngine() {
138
                if( "python".equalsIgnoreCase(this.getLangName()) ) {
139
                        List<File> libFolders = this.manager.getLibFolders();
140
                        if (libFolders == null || libFolders.size() < 1) {
141
                                return null;
142
                        }
143
                        StringBuffer buffer = new StringBuffer();
144
                        buffer.append("import sys\n");
145
                        for (File file : libFolders) {
146
                                buffer.append("sys.path.append(r'");
147
                                buffer.append(file.getAbsolutePath());
148
                                buffer.append("')\n");
149
                        }
150
                        buffer.append("load = script.load\n");
151
                        return buffer.toString();
152
                }
153
                return null;
154
        }
155
        
156
        protected ScriptEngine getEngine() {
157
                if (this.engine == null) {
158
                        ScriptEngine scriptEngine = this.manager.getEngine(this
159
                                        .getLangName());
160
                        scriptEngine.put("script", this);
161
                        this.engine = scriptEngine;
162
                        try {
163
                                String code = this.getCodeToInitializeEngine();
164
                                if( code != null ) {
165
                                        this.engine.eval(code);
166
                                }
167
                        } catch(Exception ex) {
168
                                logger.warn("Can't initialize engine with the code:\n"+code);
169
                        }
170
                }
171
                return this.engine;
172
        }
173

    
174
        protected void loadInf(Ini prefs) {
175
                super.loadInf(prefs);
176

    
177
                this.setMainName((String) getInfValue(prefs, "Script", "main", "main"));
178
                this.setLangName((String) getInfValue(prefs, "Script", "Lang",
179
                                this.getLangName()));
180
        }
181

    
182
        public void load(ScriptingFolder folder, String id) {
183
                this.setId(id);
184
                this.setParent(folder);
185

    
186
                Map<String, String> languages = this.manager
187
                                .getSupportedLanguagesByExtension();
188
                String extension = FilenameUtils.getExtension(id);
189
                String langName = languages.get(extension);
190
                this.setLangName(langName);
191
                this.setExtension(extension);
192

    
193
                File f = getFileResource(".inf");
194
                if (f.isFile()) {
195
                        Ini prefs = null;
196
                        try {
197
                                prefs = new Ini(f);
198
                        } catch (Exception e) {
199
                                logger.warn("Can't load 'inf' file '"+f.getAbsolutePath()+"'.",e);
200
                        }
201
                        loadInf(prefs);
202
                }
203
                this.setSaved(true);
204
        }
205

    
206
        public void save() {
207
                File f = getFileResource(".inf");
208
                if (!f.isFile()) {
209
                        try {
210
                                f.createNewFile();
211
                        } catch (Exception e) {
212
                                logger.warn("Can't create 'inf' file '"+f.getAbsolutePath()+"'.",e);
213
                        }
214
                }
215
                Ini prefs = null;
216
                try {
217
                        prefs = new Ini(f);
218
                } catch (Exception e) {
219
                        logger.warn("Can't load 'inf' file '"+f.getAbsolutePath()+"'.",e);
220
                }
221
                save(prefs);
222
                // Guardo el codigo en el fichero
223
                File fcode = null;
224
                try {
225
                        fcode = this.getFileResource(this.getExtension());
226
                        FileUtils.write(fcode, this.getCode());
227
                } catch (Exception e) {
228
                        logger.warn("Can't write code to file '"+fcode.getAbsolutePath()+"'.",e);
229
                }
230
                this.setSaved(true);
231
        }
232

    
233
        protected void save(Ini prefs) {
234
                super.save(prefs);
235
                prefs.put("Script", "main", this.getMainName());
236
                prefs.put("Script", "Lang", this.getLangName());
237
                try {
238
                        prefs.store();
239
                } catch (IOException e) {
240
                        String fname = (prefs.getFile()==null)? "(null)" : prefs.getFile().getAbsolutePath(); 
241
                        logger.warn("Can't save inf file ("+fname+").",e);
242
                }
243

    
244
        }
245

    
246
        public String getLangName() {
247
                return this.langName;
248
        }
249

    
250
        protected void setLangName(final String langName) {
251
                this.langName = langName;
252
                this.extension = this.manager.getExtensionByLanguage(this.langName);
253
        }
254

    
255
        public String[] getIconNames() {
256
                return new String[] { 
257
                                "scripting_" + this.getLangName().toLowerCase(),
258
                                "scripting_" + this.getLangName().toLowerCase() + "_open"
259
                };
260
        }
261

    
262
        public String getMainName() {
263
                return this.mainName;
264
        }
265

    
266
        public void setMainName(final String mainName) {
267
                this.mainName = mainName;
268
        }
269

    
270
        public String getExtension() {
271
                return this.extension;
272
        }
273

    
274
        public void setExtension(final String extension) {
275
                if( !extension.startsWith(".") ) {
276
                        this.extension = "." + extension;
277
                } else {
278
                        this.extension = extension;        
279
                }
280
        }
281

    
282
        public boolean isSaved() {
283
                return this.saved;
284
        }
285

    
286
        public void addObserver(final Observer o) {
287
                this.delegatedObservable.addObserver(o);
288
        }
289

    
290
        public void deleteObserver(final Observer o) {
291
                this.delegatedObservable.deleteObserver(o);
292
        }
293

    
294
        public void deleteObservers() {
295
                this.delegatedObservable.deleteObservers();
296
        }
297

    
298
        public void put(final String name, final Object value) {
299
                this.getEngine().put(name, value);
300
        }
301

    
302
        public void compile() {
303
                if (this.compiledCode == null) {
304
                        ScriptEngine engine = this.getEngine();
305
                        if (engine instanceof Compilable) {
306
                                try {
307
                                        Compilable compilable = (Compilable) engine;
308
                                        this.compiledCode = compilable.compile(this.getPreparedCode());
309
                                        this.compiledCode.eval();
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
                                } catch (Throwable e) {
315
                                        CompileErrorException ce = new CompileErrorException(e.getMessage(), this.getName(), e);
316
                                        notifyErrors(new Exception(e), "compile");
317
                                        throw ce;
318
                                }
319
                        }
320
                }
321
        }
322

    
323
        public Object run() {
324
                return this.run(null);
325
        }
326
        
327
        public void addDisposable(Disposable disposable){
328
                //pass
329
        }
330

    
331
        public Object run(Object args[]) {
332
                if (args == null) {
333
                        args = new Object[] {};
334
                }
335
                this.compile();
336
                return this.invokeFunction(this.getMainName(), args);
337
        }
338

    
339
        public Object invokeFunction(final String name, Object args[]) {
340
                if (this.getEngine() instanceof Invocable) {
341
                        Invocable invocable = (Invocable) this.getEngine();
342
                        this.compile();
343
                        if( args == null ) {
344
                                args = new Object[] {};
345
                        }
346
                        try {
347
                                return invocable.invokeFunction(name, args);
348
                        } catch (ScriptException e) {
349
                                ExecuteErrorException ee = new ExecuteErrorException(e.getMessage(), this.getName(), e.getLineNumber(), e.getColumnNumber(), e);
350
                                notifyErrors(ee, "invoke");
351
                                throw ee;
352
                        } catch (Throwable e) {
353
                                ExecuteErrorException ee = new ExecuteErrorException(e.getMessage(), this.getName(), e);
354
                                notifyErrors(ee, "invoke");
355
                                throw ee;
356
                        }
357
                } else {
358
                        return null;
359
                }
360
        }
361

    
362
        public Object invokeMethod(final Object obj, final String name, Object[] args)
363
                        throws NoSuchMethodException {
364

    
365
                if (this.getEngine() instanceof Invocable) {
366
                        Invocable invocable = (Invocable) this.getEngine();
367
                        this.compile();
368
                        if( args == null ) {
369
                                args = new Object[] {};
370
                        }
371
                        try {
372
                                return invocable.invokeMethod(obj, name, args);
373
                        } catch (ScriptException e) {
374
                                ExecuteErrorException ee = new ExecuteErrorException(e.getMessage(), this.getName(), e.getLineNumber(), e.getColumnNumber(), e);
375
                                notifyErrors(ee, "invoke");
376
                                throw ee;
377
                        } catch (Throwable e) {
378
                                ExecuteErrorException ee = new ExecuteErrorException(e.getMessage(), this.getName(), e);
379
                                notifyErrors(ee, "invoke");
380
                                throw ee;
381
                        }
382
                } else {
383
                        return null;
384
                }
385
        }
386

    
387
        public File getResource(String filename) {
388
                return new File( this.getParent().getFile(), filename);
389
        }
390
        
391
        class ScriptTask extends AbstractMonitorableTask {
392

    
393
                ScriptingBaseScript script = null;
394
                Object[] args = null; 
395
                
396
                protected ScriptTask(ScriptingBaseScript script, Object[] args) {
397
                        super(script.getName(),false);
398
                        this.args = args;
399
                        this.script = script;
400
                        this.script.put("task",this);
401
                        this.script.put("taskStatus",this.getTaskStatus());
402
                }
403

    
404
                public void run() {
405
                        try {
406
                                console_println("Running script "+ this.script.getName()+".");
407
                                script.run(this.args);
408
                                console_println("Script "+ this.script.getName()+ " terminated.");
409
                        } catch(Throwable e) {
410
                                console_println("Stript "+ this.script.getName()+ " aborted.");
411
                        } finally {
412
                                this.taskStatus.terminate();
413
                                try {
414
                                        Thread.sleep(3000);
415
                                } catch (InterruptedException e) {
416
                                        // Ignore
417
                                }
418
                                this.taskStatus.remove(); 
419
                        }
420
                }
421
                
422
                public void showTaskStatus() {
423
                        this.taskStatus.add();
424
                }
425
        }
426
        
427
        public void runAsTask(Object[] args) {
428
                ScriptTask task = new ScriptTask(this, args);
429
                task.start();
430
        }
431

    
432
        public boolean remove() {
433
                boolean r = true;
434
                File folder = this.getParent().getFile();
435
                File f = null;
436
                try {
437
                        f = new File(folder,this.getId()+".inf");
438
                        FileUtils.forceDelete(f);
439
                } catch (IOException e) {
440
                        logger.warn("Can't remove inf file '"+f.getAbsolutePath()+"'.",e);
441
                        r = false;
442
                }
443
                try {
444
                        f = new File(folder,this.getId()+this.getExtension());
445
                        FileUtils.forceDelete(f);
446
                } catch (IOException e) {
447
                        logger.warn("Can't remove code file '"+f.getAbsolutePath()+"'.",e);
448
                        r = false;
449
                }
450
                return r;
451
        }
452

    
453
        public void create(ScriptingFolder folder, String id, String language) {
454
                this.setParent(folder);
455
                this.setId(id);
456
                if( language==null ) {
457
                        this.setLangName("python");
458
                } else {
459
                        this.setLangName(language);
460
                }
461
                this.setExtension(this.manager.getExtensionByLanguage(getLangName()));
462

    
463
                File file = new File(folder.getFile(),id +".inf");
464
                try {
465
                        file.createNewFile();
466
                } catch (IOException e) {
467
                        logger.warn("Can't create file of the dialog in '"+file.getAbsolutePath()+"'.",e);
468
                }
469

    
470
                if( "python".equalsIgnoreCase(this.getLangName()) ) {
471
                        this.setCode("\nfrom gvsig import *\n\ndef main(*args):\n    #Remove this lines and add here your code\n\n    print \"hola mundo\"\n    pass\n\n");
472
                }
473
                this.save();
474
        }
475

    
476
        public ScriptingUnit get(String name) {
477
                return this.manager.getScript(name);
478
        }
479
 }