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

History | View | Annotate | Download (27.9 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.scripting.DataFolderFound;
26
import org.gvsig.scripting.ScriptingBaseScript;
27
import org.gvsig.scripting.ScriptingDialog;
28
import org.gvsig.scripting.ScriptingExternalFile;
29
import org.gvsig.scripting.ScriptingFolder;
30
import org.gvsig.scripting.ScriptingManager;
31
import org.gvsig.scripting.ScriptingScript;
32
import org.gvsig.scripting.ScriptingUnit;
33
import org.gvsig.tools.packageutils.Version;
34
import org.gvsig.tools.resourcesstorage.ResourcesStorage;
35
import org.gvsig.tools.script.Script;
36
import org.gvsig.tools.service.spi.ProviderFactory;
37
import org.gvsig.tools.util.FolderSet;
38
import org.python.jsr223.MyPyScriptEngine;
39
import org.slf4j.Logger;
40
import org.slf4j.LoggerFactory;
41

    
42

    
43
@SuppressWarnings("UseSpecificCatch")
44
public class DefaultScriptingManager implements ScriptingManager {
45

    
46
    public static class RegisterSystemFolder {
47

    
48
        public String name;
49
        public File folder;
50

    
51
        public RegisterSystemFolder(String name, File folder) {
52
            this.name = name;
53
            this.folder = folder;
54
        }
55
    }
56

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

    
85
    public DefaultScriptingManager(ClassLoader classLoader) {
86
        this();
87
        this.classLoader = classLoader;
88
    }
89

    
90
    @Override
91
    public Object getProperty(Object key) {
92
        return properties.get(key);
93
    }
94

    
95
    @Override
96
    public void setProperty(Object key, Object val) {
97
        properties.put(key, val);
98
    }
99

    
100
    @Override
101
    public Map getExtendedProperties() {
102
        return properties;
103
    }
104

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

    
116
    private void createDefaultFolders(File home) {
117
        createFolder(new File(home, "scripts"));
118
        createFolder(new File(home, "lib"));
119
        createFolder(new File(home, "data"));
120
    }
121

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

    
131
    @Override
132
    public void setHomeFolder(File home) {
133
        if (home == null) {
134
            this.home = new File(System.getProperty("user.home"), ".gvsig-scripting");
135
        } else {
136
            this.home = home;
137
        }
138
        createDefaultFolders(this.home);
139
        LOG.info("Set scripting home to '" + this.home.getAbsolutePath() + "'");
140
        this.addLibFolder(new File(this.home, "lib"));
141
    }
142
    
143
    private DataFolderManager getDataFolderManager() {
144
        if( this.dataFolderManager==null ) {
145
            this.dataFolderManager = new DataFolderManager(this);
146
        }
147
        return this.dataFolderManager;
148
    }
149
    
150
    @Override
151
    public File getDataFolder(String id) {
152
        return this.getDataFolderManager().getDataFolder(id);
153
    }
154

    
155
    public void registerDataFolder(ScriptingFolder folderScript, String id ) {
156
        this.getDataFolderManager().registerDataFolder(folderScript, id);
157
    }
158

    
159
    @Override
160
    public List<DataFolderFound> searchOldVersions(Version currentVersion, FolderSet folder) {
161
        return this.getDataFolderManager().searchOldVersions(currentVersion, folder);
162
    }
163
    
164
    protected synchronized ScriptEngineManager getEngineManager() {
165
        if (this.engineManager == null) {
166
            this.engineManager
167
                    = classLoader == null ? new ScriptEngineManager()
168
                            : new ScriptEngineManager(classLoader);
169
            showEnginesInfo(engineManager);
170
        }
171
        return this.engineManager;
172
    }
173

    
174
    private void showEnginesInfo(ScriptEngineManager mgr) {
175
        if (LOG.isInfoEnabled()) {
176
            List<ScriptEngineFactory> factories = mgr.getEngineFactories();
177
            StringBuilder buffer = new StringBuilder();
178
            List<Object> values = new ArrayList<>();
179
            buffer.append("Scripting engines available:");
180
            for (ScriptEngineFactory factory : factories) {
181

    
182
                // Main engine info
183
                buffer
184
                        .append("\n- {}: version = {}, language = {}, langVersion = {}");
185
                values.add(factory.getEngineName());
186
                values.add(factory.getEngineVersion());
187
                values.add(factory.getLanguageName());
188
                values.add(factory.getLanguageVersion());
189

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

    
225
            }
226
            LOG.info(buffer.toString(), values.toArray());
227
        }
228
    }
229

    
230
    @Override
231
    public synchronized void loadEngines() {
232
        this.getEngineManager();
233
    }
234
    
235
    private ScriptEngine createJythonEngine() {
236
        ScriptEngineFactory factory = this.getEngineFactoryByLanguage(PYTHON_LANGUAGE_NAME);
237
        ScriptEngine engine = new MyPyScriptEngine(factory);
238
        return engine;
239
    }
240
    
241
    public ImageIcon getIcon(String name) {
242
        return this.icons.get(name);
243
    }
244

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

    
291
    @Override
292
    public synchronized Set<String> getEnginesIsolationGroups() {
293
        return this.engineGroups.keySet();
294
    }
295
    
296
    public ScriptEngineFactory getEngineFactoryByLanguage(String langName) {
297
        List<ScriptEngineFactory> factories
298
                = getEngineManager().getEngineFactories();
299

    
300
        for (ScriptEngineFactory factory : factories) {
301
            if (factory.getLanguageName().equalsIgnoreCase(langName)) {
302
                return factory;
303
            }
304
        }
305
        return null;
306
    }
307

    
308
    @Override
309
    public boolean validateUnitId(ScriptingFolder folder, String id) {
310
        File f = new File(folder.getFile(),id+".inf");
311
        return !f.exists();
312
    }
313

    
314
    public ScriptingScript createScript(ScriptingFolder folder, String id) {
315
        return this.createScript(folder, id, null);
316
    }
317
    
318
    @Override
319
    public Script createScript(String name, String code, String languaje) {
320
        ScriptingScript script = new DefaultScriptingScript(this.getUserFolder(), this, name, languaje);
321
        script.setCode(code);
322
        script.setSaved(true);
323
        return script;        
324
    }
325

    
326
    private ScriptingScript createScript(ScriptingFolder folder, String id, String language) {
327
        DefaultScriptingScript script = new DefaultScriptingScript(folder, this, id);
328
        if (!script.getFile().exists()) {
329
            script.create(folder, id, language);
330
        } else {
331
            script.load(folder, id);
332
        }
333
        return script;
334
    }
335

    
336
    public ScriptingDialog createDialog(ScriptingFolder folder, String id) {
337
        return this.createDialog(folder, id, null);
338
    }
339

    
340
    private ScriptingDialog createDialog(ScriptingFolder folder, String id, String language) {
341
        DefaultScriptingDialog dialog = new DefaultScriptingDialog(folder, this, id);
342
        if (!dialog.getFile().exists()) {
343
            dialog.create(folder, id, language);
344
        } else {
345
            dialog.load(folder, id);
346
        }
347
        return dialog;
348
    }
349

    
350
    public ScriptingFolder createFolder(ScriptingFolder folder, String id) {
351
        DefaultScriptingFolder unit = new DefaultScriptingFolder(folder, this, new File(folder.getFile(), id));
352
        unit.load(folder, id);
353
        if (!unit.getFile().exists()) {
354
            unit.create(folder, id);
355
        }
356
        return unit;
357
    }
358

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

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

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

    
460
    public ScriptingUnit getUnit(String pathName) {
461
        ScriptingUnit unit = null;
462
        String[] parts = StringUtils.split(pathName, '/');
463
        if( parts[0].equals(this.getUserFolder().getName()) ) {
464
            unit = this.getUserFolder().getUnit( 
465
                    StringUtils.join(parts, "/", 1, parts.length) 
466
            );
467
        } else if( parts[0].equals(this.getSystemFolder().getName()) ) {
468
            unit = this.getSystemFolder().getUnit( 
469
                    StringUtils.join(parts, "/", 1, parts.length) 
470
            );
471
        } 
472
        return unit;
473
    }
474
    
475
    public ScriptingUnit getUnit(File file) {
476
        ScriptingFolder folder;
477
        ScriptingUnit unit;
478

    
479
        if (file.isAbsolute()) {
480
            if( FileUtils.isSameFile(this.getRootUserFolder(), file.getParentFile()) ) {
481
                folder = this.getUserFolder();
482
                // FIXME: que pasa si esta en SystemFolder ???
483
            } else {
484
                folder = new DefaultScriptingFolder(null, this, file.getParentFile());
485
            }
486
            unit = folder.getUnit(file);
487
            return unit;
488
        } else {
489
            folder = this.getUserFolder();
490
            unit = folder.getUnit(file);
491
            if (unit != null) {
492
                return unit;
493
            }
494

    
495
            folder = this.getSystemFolder();
496
            unit = folder.getUnit(file);
497
            if (unit != null) {
498
                return unit;
499
            }
500
        }
501
        return null;
502
    }
503

    
504
    @Override
505
    public ScriptingFolder getSystemFolder() {
506
        if( this.systemFolder == null ) {
507
            this.systemFolder = new SystemFolder(this);
508
        }
509
        return  this.systemFolder;
510
    }
511

    
512
    @Override
513
    public ScriptingFolder getUserFolder() {
514
        if( this.userFolder == null ) {
515
            this.userFolder = new UserFolder(this, this.getRootUserFolder());
516
        }
517
        return  this.userFolder;
518
    }
519

    
520
    @Override
521
    public ScriptingBaseScript getScript(String name) {
522
        return (ScriptingBaseScript) findScript(null, name);
523
    }
524

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

    
568
    @Override
569
    public File getRootUserFolder() {
570
        return new File(this.getHomeFolder(), "scripts");
571
    }
572

    
573
    @Override
574
    public void registerSystemFolder(String name, File folder) {
575
        this.systemFolders.add(new RegisterSystemFolder(name, folder));
576
        LOG.info("Register system folder name '" + name + "' folder " + folder.getAbsolutePath() + "'");
577

    
578
    }
579

    
580
    public List<RegisterSystemFolder> getSystemFolders() {
581
        return this.systemFolders;
582
    }
583

    
584
    @Override
585
    public List<ScriptingFolder> getAlternativeUserFolders() {
586
        return this.alternativeUserFolders;
587
    }
588

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

    
637
    @Override
638
    public String getExtensionOfLanguage(String langName) {
639
        if (langName == null) {
640
            return null;
641
        }
642
        langName = langName.toLowerCase();
643
        initLanguages();
644
        return this.extensionOfLanguage.get(langName);
645
    }
646

    
647
    @Override
648
    public List<String> getSupportedLanguages() {
649
        List<String> languages = new ArrayList<>();
650

    
651
        initLanguages();
652
        languages.addAll(this.extensionOfLanguage.keySet());
653
        Collections.sort(languages);
654
        return languages;
655
    }
656

    
657
    public String getLanguageOfExtension(String extension) {
658
        if (extension == null) {
659
            return null;
660
        }
661
        extension = extension.toLowerCase();
662
        if (extension.startsWith(".")) {
663
            extension = extension.substring(1);
664
        }
665
        initLanguages();
666
        return this.languageOfExtension.get(extension);
667
    }
668

    
669
    @Override
670
    public Object get(String key) {
671
        return this.bindings.get(key);
672
    }
673

    
674
    @Override
675
    public void put(String key, Object value) {
676
        this.bindings.put(key, value);
677

    
678
    }
679

    
680
    @Override
681
    public ScriptingUnit createUnit(String unitType, ScriptingFolder folder, String id) {
682
        return createUnit(unitType, folder, id, null);
683
    }
684

    
685
    @Override
686
    public ScriptingUnit createUnit(String unitType, ScriptingFolder folder, String id, String language) {
687
        if (unitType.equals(UNIT_SCRIPT)) {
688
            return this.createScript(folder, id, language);
689
        }
690
        if (unitType.equals(UNIT_DIALOG)) {
691
            return this.createDialog(folder, id, language);
692
        }
693
        if (unitType.equals(UNIT_FOLDER)) {
694
            return this.createFolder(folder, id);
695
        }
696
        if (unitType.equals(UNIT_EXTERNALFILE)) {
697
            return this.createExternalFile(folder, id);
698
        }
699
        return null;
700
    }
701

    
702
    @Override
703
    public List<String> getUnitTypes() {
704
        if (this.unitTypes == null) {
705
            this.unitTypes = new ArrayList<>();
706
            this.unitTypes.add(UNIT_SCRIPT);
707
            this.unitTypes.add(UNIT_DIALOG);
708
            this.unitTypes.add(UNIT_FOLDER);
709
            this.unitTypes.add(UNIT_EXTERNALFILE);
710
        }
711
        return this.unitTypes;
712
    }
713

    
714
    @Override
715
    public void addLibFolder(File lib) {
716
        if (lib.exists()) {
717
            LOG.info("Add scripting lib folder '" + lib.getAbsolutePath() + "'");
718
            this.libFolders.add(lib);
719
        } else {
720
            LOG.info("Skip add scripting lib folder '" + lib.getAbsolutePath() + "', folder don't exist");
721
        }
722
    }
723

    
724
    @Override
725
    public List<File> getLibFolders() {
726
        return new ArrayList(this.libFolders);
727
    }
728

    
729
    @Override
730
    public Map<String, String> getLibFoldersVersions() {
731
        Map<String, String>versions = new HashMap<>();
732
        List<File> folders = this.getLibFolders();
733
        for (File folder : folders) {
734
            File parent = folder.getParentFile();
735
            File libVersions = new File(parent,folder.getName()+".versions");
736
            if( libVersions.exists() ) {
737
                this.loadLibVersions(versions, libVersions);
738
            }
739
        }
740
        if( versions.isEmpty() ) {
741
            return null;
742
        }
743
        return versions;
744
    }
745

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

    
767
    @Override
768
    public File getPackagesFolder() {
769
        return this.packagesFolder;
770
    }
771

    
772
    @Override
773
    public void setPackagesFolder(File folder) {
774
        this.packagesFolder = folder;
775
    }
776

    
777
    @Override
778
    public ScriptingFolder createLink(String name, File link, String targetPathName) {
779
        StringBuilder contents = new StringBuilder();        
780
        contents.append("[Unit]\n")
781
            .append("type = Folder\n")
782
            .append("name = ").append(name).append("\n")
783
            .append("description =\n")
784
            .append("createdBy =\n")
785
            .append("version =\n")
786
            .append("\n")
787
            .append("[Folder]\n")
788
            .append("path =").append(targetPathName).append("\n")
789
            .append("\n\n");
790

    
791
        if( link.isDirectory() ) {
792
            link = new File(link,name+".inf");
793
        } else if( !link.getName().endsWith(".inf") ) {
794
            link = new File( link.getPath() + ".inf");
795
        }
796
        if( !link.exists() ) {
797
            try {
798
                FileUtils.writeStringToFile(link, contents.toString());
799
            } catch (IOException ex) {
800
                LOG.warn("Can't create ScriptingFolder file in '" + link.getAbsolutePath() + "'.", ex);
801
            }
802
        }
803
        ScriptingFolder folder = this.getFolder(link);
804
        return folder;
805
    }
806

    
807
    @Override
808
    public ScriptingFolder createLink(String name, ScriptingFolder link, String targetPathName) {
809
        return this.createLink(name, link.getFile(), targetPathName);
810
    }
811

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