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

History | View | Annotate | Download (11.9 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
import java.util.Map;
8

    
9
import javax.script.Compilable;
10
import javax.script.CompiledScript;
11
import javax.script.Invocable;
12
import javax.script.ScriptEngine;
13
import javax.script.ScriptException;
14

    
15
import org.apache.commons.io.FileUtils;
16
import org.apache.commons.io.FilenameUtils;
17
import org.apache.commons.io.IOUtils;
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.tools.dispose.Disposable;
25
import org.gvsig.tools.observer.Observer;
26
import org.gvsig.tools.observer.impl.DelegateWeakReferencingObservable;
27
import org.gvsig.tools.task.AbstractMonitorableTask;
28
import org.ini4j.Ini;
29
import org.slf4j.Logger;
30
import org.slf4j.LoggerFactory;
31

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

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

    
46
        protected DefaultScriptingScript(ScriptingFolder parent, String typename, ScriptingManager manager, String id) {
47
                super(parent, typename, manager, id);
48
                this.setLangName("python");
49
                this.setSaved(true);
50
                this.delegatedObservable = new DelegateWeakReferencingObservable(this);
51
        }
52
        
53
        public DefaultScriptingScript(ScriptingFolder parent, ScriptingManager manager, String id) {
54
                this(parent, ScriptingManager.UNIT_SCRIPT, manager, id);
55
        }
56

    
57
        protected void notifyErrors(Exception exception, String command) {
58
                this.delegatedObservable.notifyObservers(new BaseScriptingNotifycation(
59
                                this, BaseScriptingNotifycation.RUNTIME_ERROR_NOTIFICATION,
60
                                command, exception));
61
        }
62

    
63
        public void setSaved(boolean saved) {
64
                this.saved = saved;
65
        }
66

    
67
        public String getCode() {
68
                if (this.code == null) {
69
                        File f=null;
70
                        try {
71
                                f = this.getFileResource(this.extension);
72
                                this.code = FileUtils.readFileToString(f);
73
                        } catch (IOException e) {
74
                                String fname = (f==null)? "(null)":f.getAbsolutePath();
75
                                logger.warn("Can't load code from file '"+fname+"'.");
76
                        }
77
                }
78
                return this.code;
79
        }
80

    
81
        public void setCode(String code) {
82
                this.code = code;
83
                this.engine = null;
84
                this.compiledCode = null;
85
                this.setSaved(false);
86
        }
87

    
88
        private String getPreparedCode() {
89
                return this.getCode();
90
        }
91

    
92
        protected String getCodeToInitializeEngine() {
93
                List<File> libFolders = this.manager.getLibFolders();
94
                if (libFolders == null || libFolders.size() < 1) {
95
                        return null;
96
                }
97
                StringBuffer buffer = new StringBuffer();
98
                buffer.append("import sys\n");
99
                buffer.append("sys_path = list()\n");
100
                for (File file : libFolders) {
101
                        buffer.append("sys_path.append(r'");
102
                        buffer.append(file.getAbsolutePath());
103
                        buffer.append("')\n");
104
                }
105
                buffer.append("sys.path.extend(sys_path)\n\n\n");
106
                String resname = "/org/gvsig/scripting/impl/InitializaEngine.py";
107
                InputStream code_is = this.getClass().getResourceAsStream(resname); 
108
                if( code_is != null ) {
109
                        try {
110
                                String code = IOUtils.toString(code_is);
111
                                buffer.append(code);
112
                        } catch (IOException e) {
113
                                logger.warn("Can't read code to initialize engine from resource '"+resname+"'.",e);
114
                        }
115
                } else {
116
                        logger.warn("Can't open resurce '"+resname+"'.");
117
                }
118
                return buffer.toString();
119
        }
120
        
121
        protected ScriptEngine getEngine() {
122
                if (this.engine == null) {
123
                        ScriptEngine scriptEngine = this.manager.getEngine(this
124
                                        .getLangName());
125
                        scriptEngine.put("script", this);
126
                        this.engine = scriptEngine;
127
                        try {
128
                                String code = this.getCodeToInitializeEngine();
129
                                if( code != null ) {
130
                                        this.engine.eval(code);
131
                                }
132
                        } catch(Exception ex) {
133
                                logger.warn("Can't initialize engine with the code:\n"+code);
134
                        }
135
                }
136
                return this.engine;
137
        }
138

    
139
        protected void loadInf(Ini prefs) {
140
                super.loadInf(prefs);
141

    
142
                this.setMainName((String) getInfValue(prefs, "Script", "main", "main"));
143
                this.setLangName((String) getInfValue(prefs, "Script", "Lang",
144
                                this.getLangName()));
145
        }
146

    
147
        public void load(ScriptingFolder folder, String id) {
148
                this.setId(id);
149
                this.setParent(folder);
150

    
151
                Map<String, String> languages = this.manager
152
                                .getSupportedLanguagesByExtension();
153
                String extension = FilenameUtils.getExtension(id);
154
                String langName = languages.get(extension);
155
                this.setLangName(langName);
156
                this.setExtension(extension);
157

    
158
                File f = getFileResource(".inf");
159
                if (f.isFile()) {
160
                        Ini prefs = null;
161
                        try {
162
                                prefs = new Ini(f);
163
                        } catch (Exception e) {
164
                                logger.warn("Can't load 'inf' file '"+f.getAbsolutePath()+"'.",e);
165
                        }
166
                        loadInf(prefs);
167
                }
168
                this.setSaved(true);
169
        }
170

    
171
        public void save() {
172
                File f = getFileResource(".inf");
173
                if (!f.isFile()) {
174
                        try {
175
                                f.createNewFile();
176
                        } catch (Exception e) {
177
                                logger.warn("Can't create 'inf' file '"+f.getAbsolutePath()+"'.",e);
178
                        }
179
                }
180
                Ini prefs = null;
181
                try {
182
                        prefs = new Ini(f);
183
                } catch (Exception e) {
184
                        logger.warn("Can't load 'inf' file '"+f.getAbsolutePath()+"'.",e);
185
                }
186
                save(prefs);
187
                // Guardo el codigo en el fichero
188
                File fcode = null;
189
                try {
190
                        fcode = this.getFileResource(this.getExtension());
191
                        FileUtils.write(fcode, this.getCode());
192
                } catch (Exception e) {
193
                        logger.warn("Can't write code to file '"+fcode.getAbsolutePath()+"'.",e);
194
                }
195
                this.setSaved(true);
196
        }
197

    
198
        protected void save(Ini prefs) {
199
                super.save(prefs);
200
                prefs.put("Script", "main", this.getMainName());
201
                prefs.put("Script", "Lang", this.getLangName());
202
                try {
203
                        prefs.store();
204
                } catch (IOException e) {
205
                        String fname = (prefs.getFile()==null)? "(null)" : prefs.getFile().getAbsolutePath(); 
206
                        logger.warn("Can't save inf file ("+fname+").",e);
207
                }
208

    
209
        }
210

    
211
        public String getLangName() {
212
                return this.langName;
213
        }
214

    
215
        protected void setLangName(final String langName) {
216
                this.langName = langName;
217
                this.extension = this.manager.getExtensionByLanguage(this.langName);
218
        }
219

    
220
        public String[] getIconNames() {
221
                return new String[] { 
222
                                "scripting_" + this.getLangName().toLowerCase(),
223
                                "scripting_" + this.getLangName().toLowerCase() + "_open"
224
                };
225
        }
226

    
227
        public String getMainName() {
228
                return this.mainName;
229
        }
230

    
231
        public void setMainName(final String mainName) {
232
                this.mainName = mainName;
233
        }
234

    
235
        public String getExtension() {
236
                return this.extension;
237
        }
238

    
239
        public void setExtension(final String extension) {
240
                if( !extension.startsWith(".") ) {
241
                        this.extension = "." + extension;
242
                } else {
243
                        this.extension = extension;        
244
                }
245
        }
246

    
247
        public boolean isSaved() {
248
                return this.saved;
249
        }
250

    
251
        public void addObserver(final Observer o) {
252
                this.delegatedObservable.addObserver(o);
253
        }
254

    
255
        public void deleteObserver(final Observer o) {
256
                this.delegatedObservable.deleteObserver(o);
257
        }
258

    
259
        public void deleteObservers() {
260
                this.delegatedObservable.deleteObservers();
261
        }
262

    
263
        public void put(final String name, final Object value) {
264
                this.getEngine().put(name, value);
265
        }
266

    
267
        public void compile() {
268
                if (this.compiledCode == null) {
269
                        ScriptEngine engine = this.getEngine();
270
                        if (engine instanceof Compilable) {
271
                                try {
272
                                        Compilable compilable = (Compilable) engine;
273
                                        this.compiledCode = compilable.compile(this.getPreparedCode());
274
                                        this.compiledCode.eval();
275
                                } catch (ScriptException e) {
276
                                        CompileErrorException ce = new CompileErrorException(e.getMessage(), this.getName(), e.getLineNumber(), e.getColumnNumber(), e);
277
                                        notifyErrors(ce, "compile");
278
                                        throw ce;
279
                                } catch (Throwable e) {
280
                                        CompileErrorException ce = new CompileErrorException(e.getMessage(), this.getName(), e);
281
                                        notifyErrors(new Exception(e), "compile");
282
                                        throw ce;
283
                                }
284
                        }
285
                }
286
        }
287

    
288
        public Object run() {
289
                return this.run(null);
290
        }
291
        
292
        public void addDisposable(Disposable disposable){
293
                //pass
294
        }
295

    
296
        public Object run(Object args[]) {
297
                if (args == null) {
298
                        args = new Object[] {};
299
                }
300
                this.compile();
301
                return this.invokeFunction(this.getMainName(), args);
302
        }
303

    
304
        public Object invokeFunction(final String name, Object args[]) {
305
                if (this.getEngine() instanceof Invocable) {
306
                        Invocable invocable = (Invocable) this.getEngine();
307
                        this.compile();
308
                        if( args == null ) {
309
                                args = new Object[] {};
310
                        }
311
                        try {
312
                                return invocable.invokeFunction(name, args);
313
                        } catch (ScriptException e) {
314
                                ExecuteErrorException ee = new ExecuteErrorException(e.getMessage(), this.getName(), e.getLineNumber(), e.getColumnNumber(), e);
315
                                notifyErrors(ee, "invoke");
316
                                throw ee;
317
                        } catch (Throwable e) {
318
                                ExecuteErrorException ee = new ExecuteErrorException(e.getMessage(), this.getName(), e);
319
                                notifyErrors(ee, "invoke");
320
                                throw ee;
321
                        }
322
                } else {
323
                        return null;
324
                }
325
        }
326

    
327
        public Object invokeMethod(final Object obj, final String name, Object[] args)
328
                        throws NoSuchMethodException {
329

    
330
                if (this.getEngine() instanceof Invocable) {
331
                        Invocable invocable = (Invocable) this.getEngine();
332
                        this.compile();
333
                        if( args == null ) {
334
                                args = new Object[] {};
335
                        }
336
                        try {
337
                                return invocable.invokeMethod(obj, name, args);
338
                        } catch (ScriptException e) {
339
                                ExecuteErrorException ee = new ExecuteErrorException(e.getMessage(), this.getName(), e.getLineNumber(), e.getColumnNumber(), e);
340
                                notifyErrors(ee, "invoke");
341
                                throw ee;
342
                        } catch (Throwable e) {
343
                                ExecuteErrorException ee = new ExecuteErrorException(e.getMessage(), this.getName(), e);
344
                                notifyErrors(ee, "invoke");
345
                                throw ee;
346
                        }
347
                } else {
348
                        return null;
349
                }
350
        }
351

    
352
        public File getResource(String filename) {
353
                return new File( this.getParent().getFile(), filename);
354
        }
355
        
356
        class ScriptTask extends AbstractMonitorableTask {
357

    
358
                ScriptingBaseScript script = null;
359
                Object[] args = null; 
360
                
361
                protected ScriptTask(ScriptingBaseScript script, Object[] args) {
362
                        super(script.getName(),false);
363
                        this.args = args;
364
                        this.script = script;
365
                        this.script.put("task",this);
366
                        this.script.put("taskStatus",this.getTaskStatus());
367
                }
368

    
369
                public void run() {
370
                        try {
371
                                console_println("Running script "+ this.script.getName()+".");
372
                                script.run(this.args);
373
                                console_println("Script "+ this.script.getName()+ " terminated.");
374
                        } catch(Throwable e) {
375
                                console_println("Stript "+ this.script.getName()+ " aborted.");
376
                        } finally {
377
                                this.taskStatus.terminate();
378
                                try {
379
                                        Thread.sleep(3000);
380
                                } catch (InterruptedException e) {
381
                                        // Ignore
382
                                }
383
                                this.taskStatus.remove(); 
384
                        }
385
                }
386
                
387
                public void showTaskStatus() {
388
                        this.taskStatus.add();
389
                }
390
        }
391
        
392
        public void runAsTask(Object[] args) {
393
                ScriptTask task = new ScriptTask(this, args);
394
                task.start();
395
        }
396

    
397
        public boolean remove() {
398
                boolean r = true;
399
                File folder = this.getParent().getFile();
400
                File f = null;
401
                try {
402
                        f = new File(folder,this.getId()+".inf");
403
                        FileUtils.forceDelete(f);
404
                } catch (IOException e) {
405
                        logger.warn("Can't remove inf file '"+f.getAbsolutePath()+"'.",e);
406
                        r = false;
407
                }
408
                try {
409
                        f = new File(folder,this.getId()+this.getExtension());
410
                        FileUtils.forceDelete(f);
411
                } catch (IOException e) {
412
                        logger.warn("Can't remove code file '"+f.getAbsolutePath()+"'.",e);
413
                        r = false;
414
                }
415
                return r;
416
        }
417

    
418
        public void create(ScriptingFolder folder, String id, String language) {
419
                this.setParent(folder);
420
                this.setId(id);
421
                if( language==null ) {
422
                        this.setLangName("python");
423
                } else {
424
                        this.setLangName(language);
425
                }
426
                this.setExtension(this.manager.getExtensionByLanguage(getLangName()));
427

    
428
                File file = new File(folder.getFile(),id +".inf");
429
                try {
430
                        file.createNewFile();
431
                } catch (IOException e) {
432
                        logger.warn("Can't create file of the dialog in '"+file.getAbsolutePath()+"'.",e);
433
                }
434

    
435
                if( "python".equalsIgnoreCase(this.getLangName()) ) {
436
                        this.setCode("\nfrom gvsig import *\n\ndef main():\n    #Remove this lines and add here your code\n\n    print \"hola mundo\"\n    pass\n\n");
437
                }
438
                this.save();
439
        }
440

    
441
}