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

History | View | Annotate | Download (28.3 KB)

1
package org.gvsig.scripting.impl;
2

    
3
import java.io.File;
4
import java.io.IOException;
5
import java.net.URI;
6
import java.util.ArrayList;
7
import java.util.Collections;
8
import java.util.HashMap;
9
import java.util.Iterator;
10
import java.util.List;
11
import java.util.Map;
12
import java.util.Set;
13
import java.util.regex.Matcher;
14
import java.util.regex.Pattern;
15

    
16
import javax.script.ScriptContext;
17
import javax.script.ScriptEngine;
18
import javax.script.ScriptEngineFactory;
19
import javax.script.ScriptEngineManager;
20
import javax.script.SimpleBindings;
21
import javax.swing.ImageIcon;
22
import org.apache.commons.io.IOUtils;
23

    
24
import org.apache.commons.lang3.StringUtils;
25
import org.gvsig.expressionevaluator.ExpressionEvaluatorLocator;
26
import org.gvsig.expressionevaluator.ExpressionEvaluatorManager;
27
import org.gvsig.scripting.DataFolderFound;
28
import org.gvsig.scripting.ScriptingBaseScript;
29
import org.gvsig.scripting.ScriptingDialog;
30
import org.gvsig.scripting.ScriptingExternalFile;
31
import org.gvsig.scripting.ScriptingFolder;
32
import org.gvsig.scripting.ScriptingManager;
33
import org.gvsig.scripting.ScriptingScript;
34
import org.gvsig.scripting.ScriptingUnit;
35
import org.gvsig.tools.packageutils.Version;
36
import org.gvsig.tools.resourcesstorage.FilesResourcesStorage;
37
import org.gvsig.tools.resourcesstorage.ResourcesStorage;
38
import org.gvsig.tools.script.Script;
39
import org.gvsig.tools.service.spi.ProviderFactory;
40
import org.gvsig.tools.util.FolderSet;
41
import org.python.jsr223.MyPyScriptEngine;
42
import org.slf4j.Logger;
43
import org.slf4j.LoggerFactory;
44

    
45

    
46
@SuppressWarnings("UseSpecificCatch")
47
public class DefaultScriptingManager implements ScriptingManager {
48

    
49
    public static class RegisterSystemFolder {
50

    
51
        public String name;
52
        public File folder;
53

    
54
        public RegisterSystemFolder(String name, File folder) {
55
            this.name = name;
56
            this.folder = folder;
57
        }
58
    }
59

    
60
    static final Logger LOG = LoggerFactory
61
            .getLogger(DefaultScriptingManager.class);
62
    
63
    protected Map<String, ImageIcon> icons;
64
    protected List<RegisterSystemFolder> systemFolders = new ArrayList<>();
65
    protected ScriptEngineManager engineManager = null;
66
    private final SimpleBindings bindings = new SimpleBindings();
67
    private List<String> unitTypes = null;
68
    private ClassLoader classLoader = null;
69
    private final List<File> libFolders = new ArrayList<>();
70
    private File home = null;
71
    private final List<ScriptingFolder> alternativeUserFolders = new ArrayList<>();
72
    private Map<String, String> extensionOfLanguage = null;
73
    private Map<String, String> languageOfExtension = null;
74
    private File packagesFolder;
75
    private final Map properties = new HashMap();
76
    private final Map<String,ScriptEngine> engineGroups = new HashMap<>();
77
    private DataFolderManager dataFolderManager = null;
78
    private ScriptingFolder userFolder = null;
79
    private ScriptingFolder systemFolder = null;
80
    
81
    @SuppressWarnings({"OverridableMethodCallInConstructor", "LeakingThisInConstructor"})
82
    public DefaultScriptingManager() {
83
        this.classLoader = getClass().getClassLoader();
84
        this.setHomeFolder(null);
85
        this.bindings.put("ScriptingManager", this);
86
    }
87

    
88
    public DefaultScriptingManager(ClassLoader classLoader) {
89
        this();
90
        this.classLoader = classLoader;
91
    }
92

    
93
    @Override
94
    public Object getProperty(Object key) {
95
        return properties.get(key);
96
    }
97

    
98
    @Override
99
    public void setProperty(Object key, Object val) {
100
        properties.put(key, val);
101
    }
102

    
103
    @Override
104
    public Map getExtendedProperties() {
105
        return properties;
106
    }
107

    
108
    private void createFolder(File f) {
109
        if (!f.exists()) {
110
            try {
111
                FileUtils.forceMkdir(f);
112
                LOG.info("Created scripting folder '" + f.getAbsolutePath() + "'");
113
            } catch (Throwable e) {
114
                LOG.warn("Can't Create scripting folder '" + f.getAbsolutePath() + "'");
115
            }
116
        }
117
    }
118

    
119
    private void createDefaultFolders(File home) {
120
        createFolder(new File(home, "scripts"));
121
        createFolder(new File(home, "lib"));
122
        createFolder(new File(home, "data"));
123
    }
124

    
125
    @Override
126
    public File getHomeFolder() {
127
        if (!this.home.exists()) {
128
            createFolder(home);
129
            createDefaultFolders(home);
130
        }
131
        return this.home;
132
    }
133

    
134
    @Override
135
    public void setHomeFolder(File home) {
136
        if (home == null) {
137
            this.home = new File(System.getProperty("user.home"), ".gvsig-scripting");
138
        } else {
139
            this.home = home;
140
        }
141
        createDefaultFolders(this.home);
142
        LOG.info("Set scripting home to '" + this.home.getAbsolutePath() + "'");
143
        this.addLibFolder(new File(this.home, "lib"));
144
        
145
        FilesResourcesStorage resourcesStorage = new FilesResourcesStorage(this.home.getAbsolutePath());
146
        ExpressionEvaluatorManager expressionManager = ExpressionEvaluatorLocator.getManager();
147
        expressionManager.setScriptsResourcesStorage(resourcesStorage);
148
    }
149
    
150
    private DataFolderManager getDataFolderManager() {
151
        if( this.dataFolderManager==null ) {
152
            this.dataFolderManager = new DataFolderManager(this);
153
        }
154
        return this.dataFolderManager;
155
    }
156
    
157
    @Override
158
    public File getDataFolder(String id) {
159
        return this.getDataFolderManager().getDataFolder(id);
160
    }
161

    
162
    public void registerDataFolder(ScriptingFolder folderScript, String id ) {
163
        this.getDataFolderManager().registerDataFolder(folderScript, id);
164
    }
165

    
166
    @Override
167
    public List<DataFolderFound> searchOldVersions(Version currentVersion, FolderSet folder) {
168
        return this.getDataFolderManager().searchOldVersions(currentVersion, folder);
169
    }
170
    
171
    protected synchronized ScriptEngineManager getEngineManager() {
172
        if (this.engineManager == null) {
173
            this.engineManager
174
                    = classLoader == null ? new ScriptEngineManager()
175
                            : new ScriptEngineManager(classLoader);
176
            showEnginesInfo(engineManager);
177
        }
178
        return this.engineManager;
179
    }
180

    
181
    private void showEnginesInfo(ScriptEngineManager mgr) {
182
        if (LOG.isInfoEnabled()) {
183
            List<ScriptEngineFactory> factories = mgr.getEngineFactories();
184
            StringBuilder buffer = new StringBuilder();
185
            List<Object> values = new ArrayList<>();
186
            buffer.append("Scripting engines available:");
187
            for (ScriptEngineFactory factory : factories) {
188

    
189
                // Main engine info
190
                buffer
191
                        .append("\n- {}: version = {}, language = {}, langVersion = {}");
192
                values.add(factory.getEngineName());
193
                values.add(factory.getEngineVersion());
194
                values.add(factory.getLanguageName());
195
                values.add(factory.getLanguageVersion());
196

    
197
                // Aliases
198
                buffer.append("\n\t- Aliases: ");
199
                List<String> engNames = factory.getNames();
200
                int size = engNames.size();
201
                for (String name : engNames) {
202
                    size--;
203
                    buffer.append("{}");
204
                    if (size > 0) {
205
                        buffer.append(", ");
206
                    }
207
                    values.add(name);
208
                }
209
                buffer.append("\n\t- File extensions: ");
210
                List<String> extNames = factory.getExtensions();
211
                size = extNames.size();
212
                for (String name : extNames) {
213
                    size--;
214
                    buffer.append("{}");
215
                    if (size > 0) {
216
                        buffer.append(", ");
217
                    }
218
                    values.add(name);
219
                }
220
                buffer.append("\n\t- Mime types: ");
221
                List<String> mimeNames = factory.getMimeTypes();
222
                size = mimeNames.size();
223
                for (String name : mimeNames) {
224
                    size--;
225
                    buffer.append("{}");
226
                    if (size > 0) {
227
                        buffer.append(", ");
228
                    }
229
                    values.add(name);
230
                }
231

    
232
            }
233
            LOG.info(buffer.toString(), values.toArray());
234
        }
235
    }
236

    
237
    @Override
238
    public synchronized void loadEngines() {
239
        this.getEngineManager();
240
    }
241
    
242
    private ScriptEngine createJythonEngine() {
243
        ScriptEngineFactory factory = this.getEngineFactoryByLanguage(PYTHON_LANGUAGE_NAME);
244
        ScriptEngine engine = new MyPyScriptEngine(factory);
245
        return engine;
246
    }
247
    
248
    public ImageIcon getIcon(String name) {
249
        return this.icons.get(name);
250
    }
251

    
252
    @Override
253
    public String getEngineNameByLanguage(String langName) {
254
        ScriptEngineFactory factory = this.getEngineFactoryByLanguage(langName);
255
        if( factory == null ) {
256
            return null;
257
        }
258
        return factory.getEngineName();
259
    }
260
    
261
    public ScriptEngine getEngineByLanguage(String langName) {
262
        return this.getEngineByLanguage(langName, null);
263
    }
264
    
265
    public synchronized ScriptEngine getEngineByLanguage(String langName, String isolationGroup) {
266
        ScriptEngine engine = null;
267
        if( !StringUtils.isEmpty(isolationGroup) ) {
268
            isolationGroup += "-" + langName;
269
            engine = this.engineGroups.get(isolationGroup.toLowerCase());
270
        } 
271
        if( engine == null ) {
272
            if( PYTHON_LANGUAGE_NAME.equalsIgnoreCase(langName) ) {
273
                engine = createJythonEngine();
274
            } else {
275
                ScriptEngineFactory factory = this.getEngineFactoryByLanguage(langName);
276
                if( factory == null ) {
277
                    return null;
278
                }
279
                engine = factory.getScriptEngine();
280
            }
281
//            if( SCALA_LANGUAGE_NAME.equalsIgnoreCase(langName) ) {
282
//                try {
283
//                    // https://gist.github.com/takawitter/5479445
284
//                    Object settings = engine.getClass().getMethod("settings", new Class[0]).invoke(engine, new Object[0]);
285
//                    settings.getClass().getMethod("processArgumentString", new Class[] { String.class }).invoke(settings, new String[] { "-usejavacp"});
286
//                } catch(Throwable th) {
287
//                    LOG.warn("Can't initialice scala setting -usejavacp",th);
288
//                }
289
//            }            
290
            if( !StringUtils.isEmpty(isolationGroup) ) {
291
                this.engineGroups.put(isolationGroup.toLowerCase(), engine);
292
            }
293
        }
294
        engine.getBindings(ScriptContext.ENGINE_SCOPE).putAll(bindings);
295
        return engine;
296
    }
297

    
298
    @Override
299
    public synchronized Set<String> getEnginesIsolationGroups() {
300
        return this.engineGroups.keySet();
301
    }
302
    
303
    public ScriptEngineFactory getEngineFactoryByLanguage(String langName) {
304
        List<ScriptEngineFactory> factories
305
                = getEngineManager().getEngineFactories();
306

    
307
        for (ScriptEngineFactory factory : factories) {
308
            if (factory.getLanguageName().equalsIgnoreCase(langName)) {
309
                return factory;
310
            }
311
        }
312
        return null;
313
    }
314

    
315
    @Override
316
    public boolean validateUnitId(ScriptingFolder folder, String id) {
317
        File f = new File(folder.getFile(),id+".inf");
318
        return !f.exists();
319
    }
320

    
321
    public ScriptingScript createScript(ScriptingFolder folder, String id) {
322
        return this.createScript(folder, id, null);
323
    }
324
    
325
    @Override
326
    public Script createScript(String name, String code, String languaje) {
327
        ScriptingScript script = new DefaultScriptingScript(this.getUserFolder(), this, name, languaje);
328
        script.setCode(code);
329
        script.setSaved(true);
330
        return script;        
331
    }
332

    
333
    private ScriptingScript createScript(ScriptingFolder folder, String id, String language) {
334
        DefaultScriptingScript script = new DefaultScriptingScript(folder, this, id);
335
        if (!script.getFile().exists()) {
336
            script.create(folder, id, language);
337
        } else {
338
            script.load(folder, id);
339
        }
340
        return script;
341
    }
342

    
343
    public ScriptingDialog createDialog(ScriptingFolder folder, String id) {
344
        return this.createDialog(folder, id, null);
345
    }
346

    
347
    private ScriptingDialog createDialog(ScriptingFolder folder, String id, String language) {
348
        DefaultScriptingDialog dialog = new DefaultScriptingDialog(folder, this, id);
349
        if (!dialog.getFile().exists()) {
350
            dialog.create(folder, id, language);
351
        } else {
352
            dialog.load(folder, id);
353
        }
354
        return dialog;
355
    }
356

    
357
    public ScriptingFolder createFolder(ScriptingFolder folder, String id) {
358
        DefaultScriptingFolder unit = new DefaultScriptingFolder(folder, this, new File(folder.getFile(), id));
359
        unit.load(folder, id);
360
        if (!unit.getFile().exists()) {
361
            unit.create(folder, id);
362
        }
363
        return unit;
364
    }
365

    
366
    public ScriptingExternalFile createExternalFile(ScriptingFolder folder, String id) {
367
        DefaultScriptingExternalFile unit = new DefaultScriptingExternalFile(folder, this, id);
368
        if( unit.getExternalFile()!=null && !unit.getExternalFile().exists() ) {
369
            unit.create(folder, id);
370
        }
371
        return unit;
372
    }
373
    
374
    @Override
375
    public ScriptingBaseScript getScript(File file) {
376
        ScriptingBaseScript script = (ScriptingBaseScript) this.getUnit(file);
377
        if (script == null) {
378
            throw new ScriptNotFoundException(file);
379
        }
380
        return script;
381
    }
382
    
383
    @Override
384
    public Script loadScript(URI uri) {
385
        File f = new File(uri);
386
        try {
387
            return (Script) this.getScript(f);
388
        } catch(ScriptNotFoundException ex) {
389
            throw ex;
390
        } catch(Throwable th) {
391
            throw new ScriptNotFoundException(f);
392
        }
393
    }
394

    
395
    private static final Pattern RE_LANG = Pattern.compile(".*lang[:]\\s*([a-zA-Z_][a-zA-Z_0-9]*)");
396
    private static final Pattern RE_ENCODING = Pattern.compile(".*encoding[:]\\s*([a-zA-Z_][a-zA-Z_0-9]*)");
397
    
398
    public Script loadScript(ResourcesStorage storage, String name) {
399
        ResourcesStorage.Resource res = null;
400
        try {
401
            if( storage==null ) {
402
                return null;
403
            }
404
            res = storage.getResource(name);
405
            if( res == null || !res.exists() ) {
406
                return null;
407
            }
408
            byte[] head_bytes = new byte[500];
409
            IOUtils.read(res.asInputStream(), head_bytes);
410
            IOUtils.closeQuietly(res);
411
            String head = new String(head_bytes);
412
            if( StringUtils.isEmpty(head) ) {
413
                return null;
414
            }
415
            head = head.split("\n")[0];
416
            
417
            String lang = "python";
418
            String encoding = null;
419
            Matcher m = RE_LANG.matcher(head);
420
            if( m.groupCount()==1 ) {
421
                String s = m.group(1);
422
                if( !StringUtils.isBlank(s) ) {
423
                    lang = s;
424
                }
425
            }
426
            m = RE_ENCODING.matcher(head);
427
            if( m.groupCount()==1 ) {
428
                String s = m.group(1);
429
                if( !StringUtils.isBlank(s) ) {
430
                    encoding = s;
431
                }
432
            }
433

    
434
            String source;
435
            if( StringUtils.isBlank(encoding) ) {
436
                source = IOUtils.toString(res.asInputStream());
437
            } else {
438
                source = IOUtils.toString(res.asInputStream(), encoding);
439
            }
440
            Script script = this.createScript(name, source, lang);
441
            return script;
442
        } catch (Exception ex) {
443
            LOG.warn("Can't load script from resources storage.", ex);
444
            return null;
445
        } finally {
446
            IOUtils.closeQuietly(res);
447
        }
448
    }
449
    
450
    @Override
451
    public ScriptingFolder getFolder(File file) {
452
        if( file == null ) {
453
            throw new IllegalArgumentException("file argument can't be null");
454
        }
455
        file = this.getLinkSource(file);
456
        if( FileUtils.isSameFile(this.getRootUserFolder(),file) ) {
457
            return this.getUserFolder();
458
        }
459
        
460
        ScriptingFolder folder = (ScriptingFolder) this.getUnit(file);
461
        if (folder == null) {
462
            throw new IllegalArgumentException("Can't get ScriptFolder from '"+file.getAbsolutePath()+"'.");
463
        }
464
        return folder;
465
    }
466

    
467
    public ScriptingUnit getUnit(String pathName) {
468
        ScriptingUnit unit = null;
469
        String[] parts = StringUtils.split(pathName, '/');
470
        if( parts[0].equals(this.getUserFolder().getName()) ) {
471
            unit = this.getUserFolder().getUnit( 
472
                    StringUtils.join(parts, "/", 1, parts.length) 
473
            );
474
        } else if( parts[0].equals(this.getSystemFolder().getName()) ) {
475
            unit = this.getSystemFolder().getUnit( 
476
                    StringUtils.join(parts, "/", 1, parts.length) 
477
            );
478
        } 
479
        return unit;
480
    }
481
    
482
    public ScriptingUnit getUnit(File file) {
483
        ScriptingFolder folder;
484
        ScriptingUnit unit;
485

    
486
        if (file.isAbsolute()) {
487
            if( FileUtils.isSameFile(this.getRootUserFolder(), file.getParentFile()) ) {
488
                folder = this.getUserFolder();
489
                // FIXME: que pasa si esta en SystemFolder ???
490
            } else {
491
                folder = new DefaultScriptingFolder(null, this, file.getParentFile());
492
            }
493
            unit = folder.getUnit(file);
494
            return unit;
495
        } else {
496
            folder = this.getUserFolder();
497
            unit = folder.getUnit(file);
498
            if (unit != null) {
499
                return unit;
500
            }
501

    
502
            folder = this.getSystemFolder();
503
            unit = folder.getUnit(file);
504
            if (unit != null) {
505
                return unit;
506
            }
507
        }
508
        return null;
509
    }
510

    
511
    @Override
512
    public ScriptingFolder getSystemFolder() {
513
        if( this.systemFolder == null ) {
514
            this.systemFolder = new SystemFolder(this);
515
        }
516
        return  this.systemFolder;
517
    }
518

    
519
    @Override
520
    public ScriptingFolder getUserFolder() {
521
        if( this.userFolder == null ) {
522
            this.userFolder = new UserFolder(this, this.getRootUserFolder());
523
        }
524
        return  this.userFolder;
525
    }
526

    
527
    @Override
528
    public ScriptingBaseScript getScript(String name) {
529
        return (ScriptingBaseScript) findScript(null, name);
530
    }
531

    
532
    @Override
533
    public Script locateScript(String name) {
534
        ScriptingUnit script = findScript(null, name);
535
        if( script instanceof Script ) {
536
            return (Script) script;
537
        }
538
        return null;
539
    }
540
    
541
    private ScriptingUnit findScript(ScriptingFolder folder, String name) {
542
        if (name == null) {
543
            return null;
544
        }
545
        if (name.trim().length() == 0) {
546
            return null;
547
        }
548
        ScriptingUnit unit;
549
        if (folder == null) {
550
            unit = findScript(this.getUserFolder(), name);
551
            if (unit != null) {
552
                return unit;
553
            }
554
            unit = findScript(this.getSystemFolder(), name);
555
            return unit;
556
        }
557
        List<ScriptingUnit> units = folder.getUnits();
558
        Iterator<ScriptingUnit> it = units.iterator();
559
        while (it.hasNext()) {
560
            unit = it.next();
561
            if (unit instanceof ScriptingFolder) {
562
                unit = findScript((ScriptingFolder) unit, name);
563
                if (unit != null) {
564
                    return unit;
565
                }
566
            } else if (unit instanceof ScriptingBaseScript) {
567
                if (name.equalsIgnoreCase(unit.getId())) {
568
                    return unit;
569
                }
570
            }
571
        }
572
        return null;
573
    }
574

    
575
    @Override
576
    public File getRootUserFolder() {
577
        return new File(this.getHomeFolder(), "scripts");
578
    }
579

    
580
    @Override
581
    public void registerSystemFolder(String name, File folder) {
582
        this.systemFolders.add(new RegisterSystemFolder(name, folder));
583
        LOG.info("Register system folder name '" + name + "' folder " + folder.getAbsolutePath() + "'");
584

    
585
    }
586

    
587
    public List<RegisterSystemFolder> getSystemFolders() {
588
        return this.systemFolders;
589
    }
590

    
591
    @Override
592
    public List<ScriptingFolder> getAlternativeUserFolders() {
593
        return this.alternativeUserFolders;
594
    }
595

    
596
    @Override
597
    public void addAlternativeUserFolder(File f, String name, String description) {
598
        UserFolder x = new UserFolder(this, f);
599
        x.setName(name);
600
        x.setDescription(description);
601
        x.setId("UserFolder_" + this.alternativeUserFolders.size() + 1);
602
        this.alternativeUserFolders.add(x);
603
    }
604
    
605
    private void initLanguages() {
606
        if (this.extensionOfLanguage == null) {
607
            Map<String, String> theExtensionOfLanguage = new HashMap<>();
608
            List<ScriptEngineFactory> factories = getEngineManager().getEngineFactories();
609
            for (ScriptEngineFactory factory : factories) {
610
                if( "ognl".equals(factory.getLanguageName()) ) {
611
                    continue;
612
                }
613
                List<String> extensions = factory.getExtensions();
614
                if (extensions != null && !extensions.isEmpty()) {
615
                    theExtensionOfLanguage.put(
616
                            factory.getLanguageName().toLowerCase(),
617
                            extensions.get(0).toLowerCase()
618
                    );
619
                }
620
            }
621
            this.extensionOfLanguage = theExtensionOfLanguage;
622
        }
623
        if (this.languageOfExtension == null) {
624
            Map<String, String> theLanguageOfExtension = new HashMap<>();
625
            List<ScriptEngineFactory> factories = getEngineManager().getEngineFactories();
626
            for (ScriptEngineFactory factory : factories) {
627
                if( "ognl".equals(factory.getLanguageName()) ) {
628
                    continue;
629
                }
630
                List<String> extensions = factory.getExtensions();
631
                if (extensions != null) {
632
                    for (String extension1 : extensions) {
633
                        theLanguageOfExtension.put(
634
                                extension1.toLowerCase(),
635
                                factory.getLanguageName().toLowerCase()
636
                        );
637
                    }
638
                }
639
            }
640
            this.languageOfExtension = theLanguageOfExtension;
641
        }
642
    }
643

    
644
    @Override
645
    public String getExtensionOfLanguage(String langName) {
646
        if (langName == null) {
647
            return null;
648
        }
649
        langName = langName.toLowerCase();
650
        initLanguages();
651
        return this.extensionOfLanguage.get(langName);
652
    }
653

    
654
    @Override
655
    public List<String> getSupportedLanguages() {
656
        List<String> languages = new ArrayList<>();
657

    
658
        initLanguages();
659
        languages.addAll(this.extensionOfLanguage.keySet());
660
        Collections.sort(languages);
661
        return languages;
662
    }
663

    
664
    public String getLanguageOfExtension(String extension) {
665
        if (extension == null) {
666
            return null;
667
        }
668
        extension = extension.toLowerCase();
669
        if (extension.startsWith(".")) {
670
            extension = extension.substring(1);
671
        }
672
        initLanguages();
673
        return this.languageOfExtension.get(extension);
674
    }
675

    
676
    @Override
677
    public Object get(String key) {
678
        return this.bindings.get(key);
679
    }
680

    
681
    @Override
682
    public void put(String key, Object value) {
683
        this.bindings.put(key, value);
684

    
685
    }
686

    
687
    @Override
688
    public ScriptingUnit createUnit(String unitType, ScriptingFolder folder, String id) {
689
        return createUnit(unitType, folder, id, null);
690
    }
691

    
692
    @Override
693
    public ScriptingUnit createUnit(String unitType, ScriptingFolder folder, String id, String language) {
694
        if (unitType.equals(UNIT_SCRIPT)) {
695
            return this.createScript(folder, id, language);
696
        }
697
        if (unitType.equals(UNIT_DIALOG)) {
698
            return this.createDialog(folder, id, language);
699
        }
700
        if (unitType.equals(UNIT_FOLDER)) {
701
            return this.createFolder(folder, id);
702
        }
703
        if (unitType.equals(UNIT_EXTERNALFILE)) {
704
            return this.createExternalFile(folder, id);
705
        }
706
        return null;
707
    }
708

    
709
    @Override
710
    public List<String> getUnitTypes() {
711
        if (this.unitTypes == null) {
712
            this.unitTypes = new ArrayList<>();
713
            this.unitTypes.add(UNIT_SCRIPT);
714
            this.unitTypes.add(UNIT_DIALOG);
715
            this.unitTypes.add(UNIT_FOLDER);
716
            this.unitTypes.add(UNIT_EXTERNALFILE);
717
        }
718
        return this.unitTypes;
719
    }
720

    
721
    @Override
722
    public void addLibFolder(File lib) {
723
        if (lib.exists()) {
724
            LOG.info("Add scripting lib folder '" + lib.getAbsolutePath() + "'");
725
            this.libFolders.add(lib);
726
        } else {
727
            LOG.info("Skip add scripting lib folder '" + lib.getAbsolutePath() + "', folder don't exist");
728
        }
729
    }
730

    
731
    @Override
732
    public List<File> getLibFolders() {
733
        return new ArrayList(this.libFolders);
734
    }
735

    
736
    @Override
737
    public Map<String, String> getLibFoldersVersions() {
738
        Map<String, String>versions = new HashMap<>();
739
        List<File> folders = this.getLibFolders();
740
        for (File folder : folders) {
741
            File parent = folder.getParentFile();
742
            File libVersions = new File(parent,folder.getName()+".versions");
743
            if( libVersions.exists() ) {
744
                this.loadLibVersions(versions, libVersions);
745
            }
746
        }
747
        if( versions.isEmpty() ) {
748
            return null;
749
        }
750
        return versions;
751
    }
752

    
753
    private void loadLibVersions(Map<String,String>versions, File file) {
754
        List<String> lines;
755
        try {
756
            lines = FileUtils.readLines(file);
757
        } catch (IOException ex) {
758
            LOG.warn("Can't load lib versions from '"+file+".",ex);
759
            return;
760
        }
761
        for (String line : lines) {
762
            String[] x = line.split("=");
763
            if( x.length==2 ) {
764
                versions.put(x[0], x[1]);
765
            } 
766
        }
767
    }
768
    
769
    @Override
770
    public ProviderFactory getInstallerFactory() {
771
        return new ScriptingInstallerProviderFactory();
772
    }
773

    
774
    @Override
775
    public File getPackagesFolder() {
776
        return this.packagesFolder;
777
    }
778

    
779
    @Override
780
    public void setPackagesFolder(File folder) {
781
        this.packagesFolder = folder;
782
    }
783

    
784
    @Override
785
    public ScriptingFolder createLink(String name, File link, String targetPathName) {
786
        StringBuilder contents = new StringBuilder();        
787
        contents.append("[Unit]\n")
788
            .append("type = Folder\n")
789
            .append("name = ").append(name).append("\n")
790
            .append("description =\n")
791
            .append("createdBy =\n")
792
            .append("version =\n")
793
            .append("\n")
794
            .append("[Folder]\n")
795
            .append("path =").append(targetPathName).append("\n")
796
            .append("\n\n");
797

    
798
        if( link.isDirectory() ) {
799
            link = new File(link,name+".inf");
800
        } else if( !link.getName().endsWith(".inf") ) {
801
            link = new File( link.getPath() + ".inf");
802
        }
803
        if( !link.exists() ) {
804
            try {
805
                FileUtils.writeStringToFile(link, contents.toString());
806
            } catch (IOException ex) {
807
                LOG.warn("Can't create ScriptingFolder file in '" + link.getAbsolutePath() + "'.", ex);
808
            }
809
        }
810
        ScriptingFolder folder = this.getFolder(link);
811
        return folder;
812
    }
813

    
814
    @Override
815
    public ScriptingFolder createLink(String name, ScriptingFolder link, String targetPathName) {
816
        return this.createLink(name, link.getFile(), targetPathName);
817
    }
818

    
819
    private final Map<File,File> links = new HashMap<>();
820
    
821
    public void addLink(File source, File target) {    
822
        this.links.put(FileUtils.getRealFile(target), source);
823
    }
824
    
825
    public File getLinkSource(File target) {
826
        File source = this.links.get(FileUtils.getRealFile(target));
827
        if( source == null ) {
828
            return target;
829
        }
830
        if( source.exists() ) {
831
            return source;
832
        }
833
        return target;
834
    }
835
    
836
    public boolean isInUserFolder(File f) {
837
        if( FileUtils.isSubfolder(this.getRootUserFolder(), f) ) {
838
            return true;
839
        }
840
        for( File file : this.links.keySet()) {
841
            if( FileUtils.isSubfolder(file, f) ) {
842
                return true;
843
            }
844
        }
845
        return false;
846
    }
847
}