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 / DefaultScriptingManager.java @ 952

History | View | Annotate | Download (21.8 KB)

1
package org.gvsig.scripting.impl;
2

    
3
import java.io.File;
4
import java.io.IOException;
5
import java.util.ArrayList;
6
import java.util.Collections;
7
import java.util.HashMap;
8
import java.util.Iterator;
9
import java.util.List;
10
import java.util.Map;
11
import java.util.Set;
12

    
13
import javax.script.ScriptContext;
14
import javax.script.ScriptEngine;
15
import javax.script.ScriptEngineFactory;
16
import javax.script.ScriptEngineManager;
17
import javax.script.SimpleBindings;
18
import javax.swing.ImageIcon;
19

    
20
import org.apache.commons.io.FileUtils;
21
import org.apache.commons.lang3.StringUtils;
22
import org.gvsig.scripting.ScriptingBaseScript;
23
import org.gvsig.scripting.ScriptingDialog;
24
import org.gvsig.scripting.ScriptingExternalFile;
25
import org.gvsig.scripting.ScriptingFolder;
26
import org.gvsig.scripting.ScriptingHelpManager;
27
import org.gvsig.scripting.ScriptingManager;
28
import org.gvsig.scripting.ScriptingScript;
29
import org.gvsig.scripting.ScriptingUnit;
30
import org.gvsig.tools.script.Script;
31
import org.gvsig.tools.service.spi.ProviderFactory;
32
import org.python.jsr223.MyPyScriptEngine;
33
import org.slf4j.Logger;
34
import org.slf4j.LoggerFactory;
35

    
36

    
37
public class DefaultScriptingManager implements ScriptingManager {
38

    
39
    public static class RegisterSystemFolder {
40

    
41
        public String name;
42
        public File folder;
43

    
44
        public RegisterSystemFolder(String name, File folder) {
45
            this.name = name;
46
            this.folder = folder;
47
        }
48
    }
49

    
50
    static final Logger LOG = LoggerFactory
51
            .getLogger(DefaultScriptingManager.class);
52
    
53
    protected Map<String, ImageIcon> icons;
54
    protected List<RegisterSystemFolder> systemFolders = new ArrayList<>();
55
    protected ScriptEngineManager engineManager = null;
56
    private final SimpleBindings bindings = new SimpleBindings();
57
    private ScriptingHelpManager helpManager = null;
58
    private List<String> unitTypes = null;
59
    private ClassLoader classLoader = null;
60
    private final List<File> libFolders = new ArrayList<>();
61
    private File home = null;
62
    private final List<ScriptingFolder> alternativeUserFolders = new ArrayList<>();
63
    private Map<String, String> extensionOfLanguage = null;
64
    private Map<String, String> languageOfExtension = null;
65
    private File packagesFolder;
66
    private final Map properties = new HashMap();
67
    private final Map<String,ScriptEngine> engineGroups = new HashMap<>();
68
    
69
    public DefaultScriptingManager() {
70
        this.classLoader = getClass().getClassLoader();
71
        this.setHomeFolder(null);
72
        this.bindings.put("ScriptingManager", this);
73
    }
74

    
75
    public DefaultScriptingManager(ClassLoader classLoader) {
76
        this();
77
        this.classLoader = classLoader;
78
    }
79

    
80
    @Override
81
    public Object getProperty(Object key) {
82
        return properties.get(key);
83
    }
84

    
85
    @Override
86
    public void setProperty(Object key, Object val) {
87
        properties.put(key, val);
88
    }
89

    
90
    @Override
91
    public Map getExtendedProperties() {
92
        return properties;
93
    }
94

    
95
    private void createFolder(File f) {
96
        if (!f.exists()) {
97
            try {
98
                FileUtils.forceMkdir(f);
99
                LOG.info("Created scripting folder '" + f.getAbsolutePath() + "'");
100
            } catch (Throwable e) {
101
                LOG.warn("Can't Create scripting folder '" + f.getAbsolutePath() + "'");
102
            }
103
        }
104
    }
105

    
106
    private void createDefaultFolders(File home) {
107
        createFolder(new File(home, "scripts"));
108
        createFolder(new File(home, "help"));
109
        createFolder(new File(home, "lib"));
110
    }
111

    
112
    @Override
113
    public File getHomeFolder() {
114
        if (!this.home.exists()) {
115
            createFolder(home);
116
            createDefaultFolders(home);
117
        }
118
        return this.home;
119
    }
120

    
121
    @Override
122
    public void setHomeFolder(File home) {
123
        if (home == null) {
124
            this.home = new File(System.getProperty("user.home"), ".gvsig-scripting");
125
        } else {
126
            this.home = home;
127
        }
128
        createDefaultFolders(this.home);
129
        LOG.info("Set scripting home to '" + this.home.getAbsolutePath() + "'");
130
        this.addLibFolder(new File(this.home, "lib"));
131
    }
132

    
133
    protected synchronized ScriptEngineManager getEngineManager() {
134
        if (this.engineManager == null) {
135
            this.engineManager
136
                    = classLoader == null ? new ScriptEngineManager()
137
                            : new ScriptEngineManager(classLoader);
138
            showEnginesInfo(engineManager);
139
        }
140
        return this.engineManager;
141
    }
142

    
143
    private void showEnginesInfo(ScriptEngineManager mgr) {
144
        if (LOG.isInfoEnabled()) {
145
            List<ScriptEngineFactory> factories = mgr.getEngineFactories();
146
            StringBuilder buffer = new StringBuilder();
147
            List<Object> values = new ArrayList<>();
148
            buffer.append("Scripting engines available:");
149
            for (ScriptEngineFactory factory : factories) {
150

    
151
                // Main engine info
152
                buffer
153
                        .append("\n- {}: version = {}, language = {}, langVersion = {}");
154
                values.add(factory.getEngineName());
155
                values.add(factory.getEngineVersion());
156
                values.add(factory.getLanguageName());
157
                values.add(factory.getLanguageVersion());
158

    
159
                // Aliases
160
                buffer.append("\n\t- Aliases: ");
161
                List<String> engNames = factory.getNames();
162
                int size = engNames.size();
163
                for (String name : engNames) {
164
                    size--;
165
                    buffer.append("{}");
166
                    if (size > 0) {
167
                        buffer.append(", ");
168
                    }
169
                    values.add(name);
170
                }
171
                buffer.append("\n\t- File extensions: ");
172
                List<String> extNames = factory.getExtensions();
173
                size = extNames.size();
174
                for (String name : extNames) {
175
                    size--;
176
                    buffer.append("{}");
177
                    if (size > 0) {
178
                        buffer.append(", ");
179
                    }
180
                    values.add(name);
181
                }
182
                buffer.append("\n\t- Mime types: ");
183
                List<String> mimeNames = factory.getMimeTypes();
184
                size = mimeNames.size();
185
                for (String name : mimeNames) {
186
                    size--;
187
                    buffer.append("{}");
188
                    if (size > 0) {
189
                        buffer.append(", ");
190
                    }
191
                    values.add(name);
192
                }
193

    
194
            }
195
            LOG.info(buffer.toString(), values.toArray());
196
        }
197
    }
198

    
199
    @Override
200
    public synchronized void loadEngines() {
201
        this.getEngineManager();
202
    }
203
    
204
    private ScriptEngine createJythonEngine() {
205
        ScriptEngineFactory factory = this.getEngineFactoryByLanguage(PYTHON_LANGUAGE_NAME);
206
        ScriptEngine engine = new MyPyScriptEngine(factory);
207
        return engine;
208
    }
209
    
210
    public ImageIcon getIcon(String name) {
211
        return this.icons.get(name);
212
    }
213

    
214
    @Override
215
    public String getEngineNameByLanguage(String langName) {
216
        ScriptEngineFactory factory = this.getEngineFactoryByLanguage(langName);
217
        if( factory == null ) {
218
            return null;
219
        }
220
        return factory.getEngineName();
221
    }
222
    
223
    public ScriptEngine getEngineByLanguage(String langName) {
224
        return this.getEngineByLanguage(langName, null);
225
    }
226
    
227
    public synchronized ScriptEngine getEngineByLanguage(String langName, String isolationGroup) {
228
        ScriptEngine engine = null;
229
        if( !StringUtils.isEmpty(isolationGroup) ) {
230
            isolationGroup += "-" + langName;
231
            engine = this.engineGroups.get(isolationGroup.toLowerCase());
232
        } 
233
        if( engine == null ) {
234
            if( PYTHON_LANGUAGE_NAME.equalsIgnoreCase(langName) ) {
235
                engine = createJythonEngine();
236
            } else {
237
                ScriptEngineFactory factory = this.getEngineFactoryByLanguage(langName);
238
                if( factory == null ) {
239
                    return null;
240
                }
241
                engine = factory.getScriptEngine();
242
            }
243
            if( SCALA_LANGUAGE_NAME.equalsIgnoreCase(langName) ) {
244
                try {
245
                    // https://gist.github.com/takawitter/5479445
246
                    Object settings = engine.getClass().getMethod("settings", new Class[0]).invoke(engine, new Object[0]);
247
                    settings.getClass().getMethod("processArgumentString", new Class[] { String.class }).invoke(settings, new String[] { "-usejavacp"});
248
                } catch(Throwable th) {
249
                    LOG.warn("Can't initialice scala setting -usejavacp",th);
250
                }
251
            }            
252
            if( !StringUtils.isEmpty(isolationGroup) ) {
253
                this.engineGroups.put(isolationGroup.toLowerCase(), engine);
254
            }
255
        }
256
        engine.getBindings(ScriptContext.ENGINE_SCOPE).putAll(bindings);
257
        return engine;
258
    }
259

    
260
    @Override
261
    public synchronized Set<String> getEnginesIsolationGroups() {
262
        return this.engineGroups.keySet();
263
    }
264
    
265
    public ScriptEngineFactory getEngineFactoryByLanguage(String langName) {
266
        List<ScriptEngineFactory> factories
267
                = getEngineManager().getEngineFactories();
268

    
269
        for (ScriptEngineFactory factory : factories) {
270
            if (factory.getLanguageName().equalsIgnoreCase(langName)) {
271
                return factory;
272
            }
273
        }
274
        return null;
275
    }
276

    
277
    @Override
278
    public boolean validateUnitId(ScriptingFolder folder, String id) {
279
        File f = new File(folder.getFile(),id+".inf");
280
        if( f.exists() ) {
281
            return false;
282
        }
283
        return true;
284
//        List<ScriptingUnit> units = folder.getUnits();
285
//        String fileName;
286
//        for (ScriptingUnit unit : units) {
287
//            fileName = unit.getId();
288
//            fileName = FilenameUtils.getBaseName(fileName);
289
//            if (fileName.equals(id)) {
290
//                return false;
291
//            }
292
//        }
293
//        return true;
294
    }
295

    
296
    public ScriptingScript createScript(ScriptingFolder folder, String id) {
297
        return this.createScript(folder, id, null);
298
    }
299
    
300
    @Override
301
    public Script createScript(String name, String code, String languaje) {
302
        ScriptingScript script = new DefaultScriptingScript(this.getUserFolder(), this, name);
303
        script.setCode(code);
304
        script.setSaved(true);
305
        return script;        
306
    }
307

    
308
    private ScriptingScript createScript(ScriptingFolder folder, String id, String language) {
309
        DefaultScriptingScript script = new DefaultScriptingScript(folder, this, id);
310
        if (!script.getFile().exists()) {
311
            script.create(folder, id, language);
312
        } else {
313
            script.load(folder, id);
314
        }
315
        return script;
316
    }
317

    
318
    public ScriptingDialog createDialog(ScriptingFolder folder, String id) {
319
        return this.createDialog(folder, id, null);
320
    }
321

    
322
    private ScriptingDialog createDialog(ScriptingFolder folder, String id, String language) {
323
        DefaultScriptingDialog dialog = new DefaultScriptingDialog(folder, this, id);
324
        if (!dialog.getFile().exists()) {
325
            dialog.create(folder, id, language);
326
        } else {
327
            dialog.load(folder, id);
328
        }
329
        return dialog;
330
    }
331

    
332
    public ScriptingFolder createFolder(ScriptingFolder folder, String id) {
333
        DefaultScriptingFolder unit = new DefaultScriptingFolder(folder, this, new File(folder.getFile(), id));
334
        unit.load(folder, id);
335
        if (!unit.getFile().exists()) {
336
            unit.create(folder, id);
337
        }
338
        return unit;
339
    }
340

    
341
    public ScriptingExternalFile createExternalFile(ScriptingFolder folder, String id) {
342
        DefaultScriptingExternalFile unit = new DefaultScriptingExternalFile(folder, this, id);
343
        if( unit.getExternalFile()!=null && !unit.getExternalFile().exists() ) {
344
            unit.create(folder, id);
345
        }
346
        return unit;
347
    }
348
    
349
    @Override
350
    public ScriptingBaseScript getScript(File file) {
351
        ScriptingBaseScript script = (ScriptingBaseScript) this.getUnit(file);
352
        if (script == null) {
353
            throw new ScriptNotFoundException(file);
354
        }
355
        return script;
356
    }
357

    
358
    @Override
359
    public ScriptingFolder getFolder(File file) {
360
        ScriptingFolder folder = (ScriptingFolder) this.getUnit(file);
361
        if (folder == null) {
362
            throw new RuntimeException(file.getAbsolutePath());
363
        }
364
        return folder;
365
    }
366

    
367
    public ScriptingUnit getUnit(File file) {
368
        ScriptingFolder folder;
369
        ScriptingUnit unit;
370

    
371
        if (file.isAbsolute()) {
372
            folder = new DefaultScriptingFolder(null, this, file.getParentFile());
373
            unit = folder.getUnit(file);
374
            return unit;
375
        } else {
376
            folder = this.getUserFolder();
377
            unit = folder.getUnit(file);
378
            if (unit != null) {
379
                return unit;
380
            }
381

    
382
            folder = this.getSystemFolder();
383
            unit = folder.getUnit(file);
384
            if (unit != null) {
385
                return unit;
386
            }
387
        }
388
        return null;
389
    }
390

    
391
    @Override
392
    public ScriptingFolder getSystemFolder() {
393
        return new SystemFolder(this);
394
    }
395

    
396
    @Override
397
    public ScriptingFolder getUserFolder() {
398
        return new UserFolder(this, this.getRootUserFolder());
399
    }
400

    
401
    @Override
402
    public ScriptingBaseScript getScript(String name) {
403
        return (ScriptingBaseScript) findScript(null, name);
404
    }
405

    
406
    public Script locateScript(String name) {
407
        ScriptingUnit script = findScript(null, name);
408
        if( script instanceof Script ) {
409
            return (Script) script;
410
        }
411
        return null;
412
    }
413
    
414
    private ScriptingUnit findScript(ScriptingFolder folder, String name) {
415
        if (name == null) {
416
            return null;
417
        }
418
        if (name.trim().length() == 0) {
419
            return null;
420
        }
421
        ScriptingUnit unit;
422
        if (folder == null) {
423
            unit = findScript(this.getUserFolder(), name);
424
            if (unit != null) {
425
                return unit;
426
            }
427
            unit = findScript(this.getSystemFolder(), name);
428
            return unit;
429
        }
430
        List<ScriptingUnit> units = folder.getUnits();
431
        Iterator<ScriptingUnit> it = units.iterator();
432
        while (it.hasNext()) {
433
            unit = it.next();
434
            if (unit instanceof ScriptingFolder) {
435
                unit = findScript((ScriptingFolder) unit, name);
436
                if (unit != null) {
437
                    return unit;
438
                }
439
            } else if (unit instanceof ScriptingBaseScript) {
440
                if (name.equalsIgnoreCase(unit.getId())) {
441
                    return unit;
442
                }
443
            }
444
        }
445
        return null;
446
    }
447

    
448
    @Override
449
    public File getRootUserFolder() {
450
        return new File(this.getHomeFolder(), "scripts");
451
    }
452

    
453
    @Override
454
    public void registerSystemFolder(String name, File folder) {
455
        this.systemFolders.add(new RegisterSystemFolder(name, folder));
456
        LOG.info("Register system folder name '" + name + "' folder " + folder.getAbsolutePath() + "'");
457

    
458
    }
459

    
460
    public List<RegisterSystemFolder> getSystemFolders() {
461
        return this.systemFolders;
462
    }
463

    
464
    @Override
465
    public List<ScriptingFolder> getAlternativeUserFolders() {
466
        return this.alternativeUserFolders;
467
    }
468

    
469
    @Override
470
    public void addAlternativeUserFolder(File f, String name, String description) {
471
        UserFolder x = new UserFolder(this, f);
472
        x.setName(name);
473
        x.setDescription(description);
474
        x.setId("UserFolder_" + this.alternativeUserFolders.size() + 1);
475
        this.alternativeUserFolders.add(x);
476
    }
477
    
478
    private void initLanguages() {
479
        if (this.extensionOfLanguage == null) {
480
            Map<String, String> extensionOfLanguage = new HashMap<>();
481
            List<ScriptEngineFactory> factories = getEngineManager().getEngineFactories();
482
            for (ScriptEngineFactory factory : factories) {
483
                if( "ognl".equals(factory.getLanguageName()) ) {
484
                    continue;
485
                }
486
                List<String> extensions = factory.getExtensions();
487
                if (extensions != null && !extensions.isEmpty()) {
488
                    extensionOfLanguage.put(
489
                            factory.getLanguageName().toLowerCase(),
490
                            extensions.get(0).toLowerCase()
491
                    );
492
                }
493
            }
494
            this.extensionOfLanguage = extensionOfLanguage;
495
        }
496
        if (this.languageOfExtension == null) {
497
            Map<String, String> languageOfExtension = new HashMap<>();
498
            List<ScriptEngineFactory> factories = getEngineManager().getEngineFactories();
499
            for (ScriptEngineFactory factory : factories) {
500
                if( "ognl".equals(factory.getLanguageName()) ) {
501
                    continue;
502
                }
503
                List<String> extensions = factory.getExtensions();
504
                if (extensions != null) {
505
                    for (String extension1 : extensions) {
506
                        languageOfExtension.put(
507
                                extension1.toLowerCase(),
508
                                factory.getLanguageName().toLowerCase()
509
                        );
510
                    }
511
                }
512
            }
513
            this.languageOfExtension = languageOfExtension;
514
        }
515
    }
516

    
517
    @Override
518
    public String getExtensionOfLanguage(String langName) {
519
        if (langName == null) {
520
            return null;
521
        }
522
        langName = langName.toLowerCase();
523
        initLanguages();
524
        return this.extensionOfLanguage.get(langName);
525
    }
526

    
527
    @Override
528
    public List<String> getSupportedLanguages() {
529
        List<String> languages = new ArrayList<>();
530

    
531
        initLanguages();
532
        languages.addAll(this.extensionOfLanguage.keySet());
533
        Collections.sort(languages);
534
        return languages;
535
    }
536

    
537
    public String getLanguageOfExtension(String extension) {
538
        if (extension == null) {
539
            return null;
540
        }
541
        extension = extension.toLowerCase();
542
        if (extension.startsWith(".")) {
543
            extension = extension.substring(1);
544
        }
545
        initLanguages();
546
        return this.languageOfExtension.get(extension);
547
    }
548

    
549
    @Override
550
    public Object get(String key) {
551
        return this.bindings.get(key);
552
    }
553

    
554
    @Override
555
    public void put(String key, Object value) {
556
        this.bindings.put(key, value);
557

    
558
    }
559

    
560
    @Override
561
    public ScriptingHelpManager getHelpManager() {
562
        if (this.helpManager == null) {
563
            this.helpManager = new DefaultScriptingHelpManager(this);
564
        }
565
        return this.helpManager;
566
    }
567

    
568
    @Override
569
    public ScriptingUnit createUnit(String unitType, ScriptingFolder folder, String id) {
570
        return createUnit(unitType, folder, id, null);
571
    }
572

    
573
    @Override
574
    public ScriptingUnit createUnit(String unitType, ScriptingFolder folder, String id, String language) {
575
        if (unitType.equals(UNIT_SCRIPT)) {
576
            return this.createScript(folder, id, language);
577
        }
578
        if (unitType.equals(UNIT_DIALOG)) {
579
            return this.createDialog(folder, id, language);
580
        }
581
        if (unitType.equals(UNIT_FOLDER)) {
582
            return this.createFolder(folder, id);
583
        }
584
        if (unitType.equals(UNIT_EXTERNALFILE)) {
585
            return this.createExternalFile(folder, id);
586
        }
587
        return null;
588
    }
589

    
590
    @Override
591
    public List<String> getUnitTypes() {
592
        if (this.unitTypes == null) {
593
            this.unitTypes = new ArrayList<>();
594
            this.unitTypes.add(UNIT_SCRIPT);
595
            this.unitTypes.add(UNIT_DIALOG);
596
            this.unitTypes.add(UNIT_FOLDER);
597
            this.unitTypes.add(UNIT_EXTERNALFILE);
598
        }
599
        return this.unitTypes;
600
    }
601

    
602
    @Override
603
    public void addLibFolder(File lib) {
604
        if (lib.exists()) {
605
            LOG.info("Add scripting lib folder '" + lib.getAbsolutePath() + "'");
606
            this.libFolders.add(lib);
607
        } else {
608
            LOG.info("Skip add scripting lib folder '" + lib.getAbsolutePath() + "', folder don't exist");
609
        }
610
    }
611

    
612
    @Override
613
    public List<File> getLibFolders() {
614
        return new ArrayList(this.libFolders);
615
    }
616

    
617
    @Override
618
    public Map<String, String> getLibFoldersVersions() {
619
        Map<String, String>versions = new HashMap<>();
620
        List<File> folders = this.getLibFolders();
621
        for (File folder : folders) {
622
            File parent = folder.getParentFile();
623
            File libVersions = new File(parent,folder.getName()+".versions");
624
            if( libVersions.exists() ) {
625
                this.loadLibVersions(versions, libVersions);
626
            }
627
        }
628
        if( versions.isEmpty() ) {
629
            return null;
630
        }
631
        return versions;
632
    }
633

    
634
    private void loadLibVersions(Map<String,String>versions, File file) {
635
        List<String> lines;
636
        try {
637
            lines = FileUtils.readLines(file);
638
        } catch (IOException ex) {
639
            LOG.warn("Can't load lib versions from '"+file+".",ex);
640
            return;
641
        }
642
        for (String line : lines) {
643
            String[] x = line.split("=");
644
            if( x.length==2 ) {
645
                versions.put(x[0], x[1]);
646
            } 
647
        }
648
    }
649
    
650
    @Override
651
    public ProviderFactory getInstallerFactory() {
652
        return new ScriptingInstallerProviderFactory();
653
    }
654

    
655
    @Override
656
    public ProviderFactory getHelpInstallerFactory() {
657
        return new ScriptingHelpInstallerProviderFactory();
658
    }
659

    
660
    @Override
661
    public File getPackagesFolder() {
662
        return this.packagesFolder;
663
    }
664

    
665
    @Override
666
    public void setPackagesFolder(File folder) {
667
        this.packagesFolder = folder;
668
    }
669

    
670
}