Statistics
| Revision:

gvsig-scripting / org.gvsig.scripting / trunk / org.gvsig.scripting / org.gvsig.scripting.app / org.gvsig.scripting.app.mainplugin / src / main / java / org / gvsig / scripting / app / extension / ScriptingExtension.java @ 1047

History | View | Annotate | Download (24.2 KB)

1
/* gvSIG. Geographic Information System of the Valencian Government
2
 *
3
 * Copyright (C) 2007-2008 Infrastructures and Transports Department
4
 * of the Valencian Government (CIT)
5
 * 
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 2
9
 * of the License, or (at your option) any later version.
10
 * 
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 * 
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 
19
 * MA  02110-1301, USA.
20
 * 
21
 */
22
package org.gvsig.scripting.app.extension;
23

    
24
import java.io.File;
25
import java.io.IOException;
26
import java.io.InputStream;
27
import java.nio.file.FileVisitOption;
28
import static java.nio.file.FileVisitOption.FOLLOW_LINKS;
29
import java.nio.file.FileVisitResult;
30
import java.nio.file.Files;
31
import java.nio.file.Path;
32
import java.nio.file.Paths;
33
import java.nio.file.SimpleFileVisitor;
34
import java.nio.file.attribute.BasicFileAttributes;
35
import java.text.MessageFormat;
36
import java.util.ArrayList;
37
import java.util.Arrays;
38
import java.util.Collections;
39
import java.util.Comparator;
40
import java.util.EnumSet;
41
import java.util.List;
42
import java.util.function.Predicate;
43

    
44
import javax.swing.JOptionPane;
45
import org.apache.commons.io.FileUtils;
46
import org.apache.commons.io.FilenameUtils;
47
import org.apache.commons.io.IOCase;
48
import org.apache.commons.io.IOUtils;
49
import org.apache.commons.lang3.BooleanUtils;
50
import org.apache.commons.lang3.StringUtils;
51

    
52
import org.gvsig.andami.IconThemeHelper;
53
import org.gvsig.andami.PluginServices;
54
import org.gvsig.andami.PluginsLocator;
55
import org.gvsig.andami.PluginsManager;
56
import org.gvsig.andami.plugins.Extension;
57
import org.gvsig.app.ApplicationLocator;
58
import org.gvsig.app.ApplicationManager;
59
import org.gvsig.scripting.ScriptingBaseScript;
60
import org.gvsig.scripting.ScriptingFolder;
61
import org.gvsig.scripting.ScriptingLocator;
62
import org.gvsig.scripting.ScriptingManager;
63
import org.gvsig.scripting.ScriptingScript;
64
import org.gvsig.scripting.ScriptingUnit;
65
import org.gvsig.scripting.app.extension.messagewait.MessageWait;
66
import org.gvsig.scripting.swing.api.JScriptingComposer;
67
import org.gvsig.scripting.swing.api.ScriptingSwingLocator;
68
import org.gvsig.scripting.swing.api.ScriptingUIManager;
69
import static org.gvsig.scripting.swing.api.ScriptingUIManager.SCRIPT_COMPOSER_AUTORUN;
70
import org.gvsig.tools.dynobject.DynObject;
71
import org.gvsig.tools.swing.api.ToolsSwingLocator;
72
import org.gvsig.tools.swing.api.windowmanager.WindowManager;
73
import org.gvsig.tools.swing.impl.windowmanager.DefaultWindowManager;
74
import org.slf4j.Logger;
75
import org.slf4j.LoggerFactory;
76
import org.gvsig.tools.ToolsLocator;
77
import org.gvsig.tools.exception.BaseException;
78
import org.gvsig.tools.i18n.I18nManager;
79
import org.gvsig.tools.script.Script;
80
import org.gvsig.tools.task.SimpleTaskStatus;
81
import org.gvsig.tools.util.Invocable;
82
import org.gvsig.tools.visitor.VisitCanceledException;
83
import org.gvsig.tools.visitor.Visitor;
84

    
85
public class ScriptingExtension extends Extension {
86

    
87
    @SuppressWarnings("FieldNameHidesFieldInSuperclass")
88
    private static final Logger logger = LoggerFactory.getLogger(ScriptingExtension.class);
89

    
90
    private PluginServices plugin = null;
91

    
92
    private static final String SKIP_AUTORUNS = "skipAutoruns";
93
    
94
    /*
95
     * la funcion log y las constantes estan pensadas para usarlas desde los scripts.
96
     */
97
    public static final int INFO = 0;
98
    public static final int TRACE = 1;
99
    public static final int WARN = 2;
100
    public static final int ERROR = 3;
101
    private static boolean composer_initialized = false;
102
    private boolean executingAutorunScripts = true;
103
    private MessageWait message;
104

    
105
    public static void log(String message) {
106
        log(INFO, message, null);
107
    }
108

    
109
    public static void log(int level, String message) {
110
        log(level, message, null);
111
    }
112

    
113
    public static void log(int level, String message, Throwable th) {
114
        switch( level ) {
115
        case TRACE:
116
            logger.trace(message, th);
117
            break;
118
        case ERROR:
119
            logger.error(message, th);
120
            break;
121
        case WARN:
122
            logger.warn(message, th);
123
            break;
124
        default:
125
        case INFO:
126
            logger.info(message, th);
127
            break;
128
        }
129
    }
130

    
131
    @Override
132
    public PluginServices getPlugin() {
133
        if( this.plugin == null ) {
134
            this.plugin = PluginsLocator.getManager().getPlugin(ScriptingExtension.class);
135
        }
136
        return this.plugin;
137
    }
138

    
139
    @Override
140
    public void execute(String actionCommand) {
141
        this.execute(actionCommand, null);
142
    }
143

    
144
    @Override
145
    public void execute(String command, Object[] args) {
146
        ScriptingUIManager uimanager = ScriptingSwingLocator.getUIManager();
147
        WindowManager winmanager = ToolsSwingLocator.getWindowManager();
148

    
149
        if( "tools-scripting-launcher".equalsIgnoreCase(command) ) {
150
            winmanager.showWindow(uimanager.createLauncher().asJComponent(), uimanager.getTranslation("Scripting_Launcher"), WindowManager.MODE.TOOL);
151

    
152
        } else if( "tools-scripting-composer".equalsIgnoreCase(command) ) {
153
            I18nManager i18n = ToolsLocator.getI18nManager();
154
            message.showMessage(
155
                i18n.getTranslation("_notice"),
156
                i18n.getTranslation("_Initializing_the_scripting_plugin_Xhorizontal_ellipsisX") + "\n" + 
157
                    i18n.getTranslation("_Waiting_to_terminate"), 
158
                new MessageWait.WaitingCondition() {
159
                    private Thread th = null;
160
                    
161
                    @Override
162
                    public boolean stopWaiting() {
163
                        if( executingAutorunScripts ) {
164
                            return false;
165
                        }
166
                        if( composer_initialized ) {
167
                            return true;
168
                        }
169
                        if( th == null ) {
170
                            th = new Thread(new ExecuteScriptsFromScriptingFolders("scautorun",SCRIPT_COMPOSER_AUTORUN), "StartupScriptingComposer");
171
                            th.start();
172
                        }
173
                        return false;
174
                    }
175
                },
176
                new Runnable() {
177
                    @Override
178
                    public void run() {
179
                            showScriptingComposer();
180
                    }
181
                }
182
            );
183

    
184

    
185
        } else {
186
            ScriptingBaseScript script = uimanager.getManager().getScript(command);
187
            if( script != null ) {
188
                script.run(args);
189
            } else {
190
                ApplicationManager application = ApplicationLocator.getManager();
191
                application.messageDialog(
192
                        "Can't locate script '" + command + "'.", 
193
                        "ScriptLaunch", 
194
                        JOptionPane.OK_OPTION
195
                );
196
            }
197
        }
198
    }
199

    
200
    private void showScriptingComposer() {
201
        ScriptingUIManager uimanager = ScriptingSwingLocator.getUIManager();
202
 
203
        DynObject preferences = getPlugin().getPluginProperties();
204
        Boolean composerUseHisWindowManager = (Boolean) preferences.getDynValue("ComposerUseHisWindowManager");
205
        ScriptingUIManager uiManager = ScriptingSwingLocator.getUIManager();
206
        if( composerUseHisWindowManager ) {
207
            DefaultWindowManager winmanager = new DefaultWindowManager();
208
            uiManager.setWindowManager(winmanager);
209
        }
210
        JScriptingComposer composer = uimanager.createComposer();
211
        uiManager.showWindow(
212
            composer.asJComponent(),
213
            uimanager.getTranslation("Scripting_Composer")
214
        );
215
    }
216

    
217
    private class ExecuteScriptsFromScriptingFolders extends AbstractExecuteScripts {
218

    
219
        public ExecuteScriptsFromScriptingFolders(String title, String patternName) {
220
            super(title, patternName);
221
        }
222
        
223
        @Override
224
        public void run() {            
225
            SimpleTaskStatus status = ToolsLocator.getTaskStatusManager().createDefaultSimpleTaskStatus("Scripts startup");
226
            status.setIndeterminate();
227
            status.setAutoremove(true);
228
            status.add();
229
            final ApplicationManager application = ApplicationLocator.getManager();
230
            final I18nManager i18nManager = ToolsLocator.getI18nManager();            
231
            try {
232
                logger.info("Searching "+title+" scripts...");
233
                application.message(
234
                    i18nManager.getTranslation("_Searching_autorun_scripts_Xhorizontal_ellipsisX"),
235
                    JOptionPane.INFORMATION_MESSAGE
236
                );
237
                ScriptingManager manager = ScriptingLocator.getManager();
238
                final List<ScriptingScript> scripts = new ArrayList<>();
239
                
240
                Visitor visitor = new Visitor() {
241
                    @Override
242
                    public void visit(Object o) throws VisitCanceledException, BaseException {
243
                        ScriptingUnit unit = (ScriptingUnit) o;
244
                        if( unit instanceof ScriptingScript && 
245
                            FilenameUtils.wildcardMatch(unit.getName(), patternName, IOCase.INSENSITIVE) ) {
246
                            ScriptingScript script = (ScriptingScript) unit;
247
                            if( script.isEnabled() ) {
248
                                scripts.add(script);
249
                            } else {
250
                                logger.info("Skip "+title+" script '" + script.getFile().getAbsolutePath() + "'.");
251
                            }
252
                        }
253
                    }
254
                };
255
                Predicate<ScriptingUnit> includeFilter = new Predicate<ScriptingUnit>() {
256
                    @Override
257
                    public boolean test(ScriptingUnit unit) {
258
                        if( unit instanceof ScriptingFolder ) {
259
                            return !BooleanUtils.toBoolean(unit.getProperty(SKIP_AUTORUNS));
260
                        }
261
                        return false;
262
                    }
263
                };
264
                manager.getSystemFolder().accept(visitor, includeFilter);
265
                manager.getUserFolder().accept(visitor, includeFilter);
266
                sortScripts(scripts);
267
                executeScripts(scripts, status);
268
            } catch(Throwable th) {
269
                
270
            } finally {
271
                logger.info("Running "+title+" scripts terminated.");
272
                application.message("", JOptionPane.INFORMATION_MESSAGE);
273
                status.terminate();
274
                composer_initialized = true;
275
            }
276
        }
277
    }
278
    
279
    @Override
280
    public void initialize() {
281
        IconThemeHelper.registerIcon("action", "tools-scripting-launcher", this);
282
        IconThemeHelper.registerIcon("action", "tools-scripting-composer", this);
283
        IconThemeHelper.registerIcon("action", "tools-scripting-console-jython", this);
284
        this.message = new MessageWait();
285

    
286
        initPaths();
287
        Thread th = new Thread(new Runnable() {
288
            @Override
289
            public void run() {
290
                preloadPythonEngine();
291
            }
292
        }, "ScriptEnginesInitializer");
293
        th.start();
294
        try {
295
            th.join(3000); // force change to other thread
296
        } catch (InterruptedException ex) {
297
            // Ignore.
298
        }
299
    }
300

    
301
    private void preloadPythonEngine() {
302
        ScriptingManager manager = (ScriptingManager) ScriptingLocator.getManager();
303
        synchronized (manager) {
304
            String respath = "/scripting/langs/python/preload.py";
305
            InputStream res = this.getClass().getResourceAsStream(respath);
306
            if( res != null ) {
307
                logger.info("Scan for script engines");
308
                List<String> lines;
309
                try {
310
                    lines = IOUtils.readLines(res);
311
                    String code = StringUtils.join(lines, "\n");
312
                    logger.info("Preload python script engine");
313
                    Script script = manager.createScript(
314
                        "preload",
315
                        code,
316
                        ScriptingManager.PYTHON_LANGUAGE_NAME
317
                    );
318
                    logger.info("Preload python modules");
319
                    script.invokeFunction("main", null);
320

    
321
                } catch (Exception ex) {
322
                    logger.warn("Can't run preload script for python.", ex);
323
                }
324
                logger.info("Preload of script engines finished");
325
            }
326
        }
327
    }
328

    
329
    private File getScriptsHomeFolder() {
330
        PluginsManager pluginManager = PluginsLocator.getManager();
331
        File pluginHomeFolder = this.getPlugin().getPluginHomeFolder();
332

    
333
        File scriptsHomeFolder;
334
        File f = FileUtils.getFile(pluginHomeFolder, "scripts-folder.txt");
335
        if( f.exists() ) {
336
            try {
337
                List<String> lines = FileUtils.readLines(f);
338
                for( String line : lines ) {
339
                    line = line.trim();
340
                    if( !line.startsWith("#") ) {
341
                        scriptsHomeFolder = new File(line);
342
                        if( !scriptsHomeFolder.isAbsolute() ) {
343
                            scriptsHomeFolder = new File(pluginHomeFolder, line);
344
                        }
345
                        scriptsHomeFolder = new File(
346
                            FilenameUtils.normalizeNoEndSeparator(
347
                                scriptsHomeFolder.getAbsolutePath(),
348
                                true
349
                            )
350
                        );
351
                        if( scriptsHomeFolder.exists() ) {
352
                            return scriptsHomeFolder;
353
                        }
354
                    }
355
                }
356
            } catch (IOException ex) {
357
            }
358
        } else {
359
            try {
360
                FileUtils.touch(f);
361
            } catch (IOException ex) {
362
            }
363
        }
364
        String gvsigversion = pluginManager.getApplicationVersion().format("%M.%m.%r") ;
365
        scriptsHomeFolder = FileUtils.getFile(pluginHomeFolder, gvsigversion) ;
366
        return scriptsHomeFolder;
367
    }
368
    
369
    private void initPaths() {
370
        PluginsManager pluginManager = PluginsLocator.getManager();
371

    
372
        ScriptingManager manager = ScriptingLocator.getManager();
373
        manager.setHomeFolder(getScriptsHomeFolder());
374

    
375
        ScriptingFolder folder = manager.createLink(
376
            "Common",
377
            manager.getUserFolder(), 
378
            "../../scripts"
379
        );
380
        folder.setProperty(SKIP_AUTORUNS, BooleanUtils.toStringTrueFalse(true));
381
        folder.save();
382
//        manager.createLink(
383
//            "Previous version",
384
//            manager.getUserFolder(), 
385
//            "../../../org.gvsig.scripting.app.extension/scripts"
386
//        );
387

    
388
        List<File> pluginsFolders = new ArrayList<>();
389
        for( File f : pluginManager.getPluginsFolders() ) {
390
            pluginsFolders.addAll(Arrays.asList(f.listFiles()));
391
        }
392

    
393
        for( File pluginFolder : pluginsFolders ) {
394
            File scriptsFolder = new File(pluginFolder, "scripting/scripts");
395
            if( scriptsFolder.exists() ) {
396
                manager.registerSystemFolder(pluginFolder.getName(), scriptsFolder);
397
            }
398
            File libFolder = new File(pluginFolder, "scripting/lib");
399
            if( libFolder.exists() ) {
400
                manager.addLibFolder(libFolder);
401
            }
402
        }
403
        manager.setPackagesFolder(pluginManager.getInstallFolder());
404

    
405
        File localAddonRepositoryFolder = new File(manager.getRootUserFolder(), "addons");
406
        if( !localAddonRepositoryFolder.exists() ) {
407
            try {
408
                FileUtils.forceMkdir(localAddonRepositoryFolder);
409
            } catch (IOException ex) {
410
                logger.info("Can't create addons folder in '" + localAddonRepositoryFolder.getAbsolutePath() + "'.", ex);
411
            }
412
        }
413
        File initAddonFile = new File(localAddonRepositoryFolder, "__init__.py");
414
        if( !initAddonFile.exists() ) {
415
            try {
416
                FileUtils.touch(initAddonFile);
417
            } catch (IOException ex) {
418
                logger.info("Can't create addons __init__ file in '" + localAddonRepositoryFolder.getAbsolutePath() + "'.", ex);
419
            }
420
        }
421
    }
422

    
423
    @Override
424
    public void postInitialize() {
425
        super.postInitialize();
426
        PluginsManager pluginManager = PluginsLocator.getManager();
427
        pluginManager.addStartupTask(
428
            "ExecuteAutorunScripts",
429
            new ExecuteAutorunScriptsOnStartup(),
430
            true,
431
            600
432
        );
433

    
434
        Invocable initializer = new ScriptsInstallerInitializer();
435
        initializer.call(this.getPlugin().getPluginName());
436
    }
437

    
438
    @Override
439
    public boolean isEnabled() {
440
        return true;
441
    }
442

    
443
    @Override
444
    public boolean isVisible() {
445
        return true;
446
    }
447

    
448
    private class ExecuteAutorunScriptsOnStartup implements Runnable {
449

    
450
        @Override
451
        public void run() {
452
            Thread th = new Thread(new ExecuteScriptsFromFilesystem("autotun","autorun.inf"));
453
            th.start();
454
        }
455
    }
456

    
457
    private abstract class AbstractExecuteScripts implements Runnable {
458
        protected String patternName;
459
        protected String title;
460

    
461
        public AbstractExecuteScripts(String title, String patternName) {
462
            this.patternName = patternName;
463
            this.title = title;
464
        }
465

    
466
        private String getScriptOrderKey(ScriptingBaseScript o) {
467
            int groupOrder = 500;
468
            String groupName = "default";
469
            int scriptOrder = 500;
470
            String s = o.getProperty("autorun.group.order");
471
            if( s != null ) {
472
                try {
473
                    groupOrder = Integer.parseInt(s);
474
                } catch (Exception ex) {
475
                    // Do nothing.
476
                }
477
            }
478
            s = o.getProperty("autorun.group.name");
479
            if( s != null ) {
480
                groupName = s;
481
            }
482
            s = o.getProperty("autorun.order");
483
            if( s != null ) {
484
                try {
485
                    scriptOrder = Integer.parseInt(s);
486
                } catch (Exception ex) {
487
                    // Do nothing.
488
                }
489
            }
490
            String key = MessageFormat.format(
491
                "{0,number,000000}.{1}.{2,number,000000}",
492
                groupOrder,
493
                groupName,
494
                scriptOrder
495
            );
496
            return key;
497
        }
498

    
499
        protected void sortScripts(List<ScriptingScript> scripts) {
500
            Collections.sort(scripts, new Comparator<ScriptingBaseScript>() {
501

    
502
                @Override
503
                public int compare(ScriptingBaseScript o1, ScriptingBaseScript o2) {
504
                    return getScriptOrderKey(o2).compareToIgnoreCase(getScriptOrderKey(o1));
505
                }
506
            });
507
        }
508
        
509
        protected void executeScripts(List<ScriptingScript> scripts, SimpleTaskStatus status) {
510
            final I18nManager i18nManager = ToolsLocator.getI18nManager();
511
            final ApplicationManager application = ApplicationLocator.getManager();
512
            if( scripts!=null && !scripts.isEmpty() ) {
513
                if( status!=null ) {
514
                    status.setRangeOfValues(0, scripts.size());
515
                }
516
                int n=0;
517
                for (ScriptingBaseScript script : scripts) {
518
                    if( status!=null ) {
519
                        status.setCurValue(n++);
520
                    }
521
                    try {
522
                        logger.info("running "+title+" script '" + script.getFile().getAbsolutePath() + "' (" + getScriptOrderKey(script) + ", " + script.getIsolationGroup() + ").");
523
                        application.message(
524
                            i18nManager.getTranslation(
525
                                "_Running_autorun_script_from_XnameX",
526
                                new String[]{
527
                                        script.getFile().getParentFile().getName()}
528
                            ),
529
                            JOptionPane.INFORMATION_MESSAGE
530
                        );
531
                    } catch (Exception ex) {
532
                        // Ignore it
533
                    }
534
                    try {
535
                        script.run();
536
                    } catch (Exception ex) {
537
                        logger.warn("Can't execute "+title+" from '" + script.getFile().getAbsolutePath() + "'.", ex);
538
                    }
539
                }
540
            }
541

    
542
        }
543
    }
544
    
545
    private class ExecuteScriptsFromFilesystem extends AbstractExecuteScripts {
546

    
547
        public ExecuteScriptsFromFilesystem(String title, String patternName) {
548
            super(title, patternName);
549
        }
550
        
551
        @Override
552
        public void run() {
553
            final ApplicationManager application = ApplicationLocator.getManager();
554
            executingAutorunScripts = true;
555
            try {
556
                final ScriptingManager manager = ScriptingLocator.getManager();
557
                manager.loadEngines();
558

    
559
                final PluginsManager pluginManager = PluginsLocator.getManager();
560
                final I18nManager i18nManager = ToolsLocator.getI18nManager();
561

    
562
                final List<ScriptingScript> scripts = new ArrayList<>();
563

    
564
                List<File> pluginsFolders = new ArrayList<>();
565
                for( File pluginsFolders2 : pluginManager.getPluginsFolders() ) {
566
                    for( File pluginFolder : pluginsFolders2.listFiles()) {
567
                        File f = FileUtils.getFile(pluginFolder, "scripting","scripts");
568
                        if( f.exists() ) {
569
                            pluginsFolders.add(f);
570
                        }
571
                    }
572
                }
573

    
574
                application.message(
575
                    i18nManager.getTranslation("_Searching_autorun_scripts_Xhorizontal_ellipsisX"),
576
                    JOptionPane.INFORMATION_MESSAGE
577
                );
578

    
579
                SimpleFileVisitor<Path> visitor = new SimpleFileVisitor<Path>() {
580
                    @Override
581
                    public FileVisitResult visitFile(Path path, BasicFileAttributes bfa) throws IOException {
582
                        File file = path.toFile();
583
                        if( FilenameUtils.wildcardMatch(file.getName(), patternName, IOCase.INSENSITIVE)) {
584
                            if( file.exists() ) {
585
                                ScriptingScript script = (ScriptingScript) manager.getScript(file);
586
                                if( script.isEnabled() ) {
587
                                    scripts.add(script);
588
                                } else {
589
                                    logger.info("Skip "+title+" script '" + file.getAbsolutePath() + "'.");
590
                                }
591
                            }
592
                        }
593
                        return FileVisitResult.CONTINUE;
594
                    }
595
                };
596
                try {
597
                    EnumSet<FileVisitOption> opts = EnumSet.of(FOLLOW_LINKS);
598
                    for( File pluginFolder : pluginsFolders ) {
599
                        Files.walkFileTree(Paths.get(pluginFolder.toURI()), opts, Integer.MAX_VALUE, visitor);
600
                    }
601
                    Files.walkFileTree(Paths.get(manager.getRootUserFolder().toURI()), opts, Integer.MAX_VALUE, visitor);
602
                    List<ScriptingFolder> folders = manager.getAlternativeUserFolders();
603
                    for( ScriptingFolder folder : folders ) {
604
                        Files.walkFileTree(Paths.get(folder.getFile().toURI()), opts, Integer.MAX_VALUE, visitor);
605
                    }
606
                } catch (Exception ex) {
607
                    logger.warn("Can't execute "+title+" in home.", ex);
608
                }
609
                sortScripts(scripts);
610
                executeScripts(scripts, null);
611

    
612
            } finally {
613
                logger.info("Running "+title+" scripts terminated.");
614
                application.message("", JOptionPane.INFORMATION_MESSAGE);
615
                executingAutorunScripts = false;
616
            }
617
        }
618

    
619
    }
620
}