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

History | View | Annotate | Download (24 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
import java.util.logging.Level;
44

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

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

    
86
public class ScriptingExtension extends Extension {
87

    
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 StartupScriptingComposer(), "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
        WindowManager winmanager = ToolsSwingLocator.getWindowManager();
203

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

    
218
    private class StartupScriptingComposer implements Runnable {
219

    
220
        @Override
221
        public void run() {            
222
            SimpleTaskStatus status = ToolsLocator.getTaskStatusManager().createDefaultSimpleTaskStatus("Script composer startup");
223
            status.setIndeterminate();
224
            status.setAutoremove(true);
225
            status.add();
226
            final ApplicationManager application = ApplicationLocator.getManager();
227
            final I18nManager i18nManager = ToolsLocator.getI18nManager();            
228
            try {
229
                logger.info("Searching autorun scripts...");
230
                application.message(
231
                    i18nManager.getTranslation("_Searching_autorun_scripts_Xhorizontal_ellipsisX"),
232
                    JOptionPane.INFORMATION_MESSAGE
233
                );
234
                ScriptingManager manager = ScriptingLocator.getManager();
235
                final List<ScriptingScript> autoruns = new ArrayList<>();
236
                
237
                Visitor visitor = new Visitor() {
238
                    
239
                    @Override
240
                    public void visit(Object o) throws VisitCanceledException, BaseException {
241
                        ScriptingUnit unit = (ScriptingUnit) o;
242
                        if( unit instanceof ScriptingScript && SCRIPT_COMPOSER_AUTORUN.equalsIgnoreCase(unit.getId()) ) {
243
                            ScriptingScript autorun = (ScriptingScript) unit;
244
                            if( autorun.isEnabled() ) {
245
                                autoruns.add(autorun);
246
                            } else {
247
                                logger.info("Skip scautorun script '" + autorun.getFile().getAbsolutePath() + "'.");
248
                            }
249
                        }
250
                    }
251
                };
252
                manager.getSystemFolder().accept(visitor);
253
                manager.getUserFolder().accept(visitor, new Predicate<ScriptingUnit>() {
254
                    @Override
255
                    public boolean test(ScriptingUnit unit) {
256
                        if( unit instanceof ScriptingFolder ) {
257
                            return !BooleanUtils.toBoolean(unit.getProperty(SKIP_AUTORUNS));
258
                        }
259
                        return false;
260
                    }
261
                });
262
                if( !autoruns.isEmpty() ) {
263
                    status.setRangeOfValues(0, autoruns.size());
264
                    int n=0;
265
                    for (ScriptingScript autorun : autoruns) {
266
                        status.setCurValue(n++);
267
                        try {
268
                            logger.info("running autorun script '" + autorun.getFile().getAbsolutePath() + ".");
269
                            application.message(
270
                                i18nManager.getTranslation(
271
                                    "_Running_autorun_script_from_XnameX",
272
                                    new String[]{
273
                                            autorun.getFile().getParentFile().getName()}
274
                                ),
275
                                JOptionPane.INFORMATION_MESSAGE
276
                            );
277
                        } catch (Exception ex) {
278
                            // Ignore it
279
                        }
280
                        try {
281
                            autorun.run();
282
                        } catch (Exception ex) {
283
                            logger.warn("Can't execute autorun from '" + autorun.getFile().getAbsolutePath() + "'.", ex);
284
                        }
285
                    }
286
                }
287
            } catch(Throwable th) {
288
                
289
            } finally {
290
                logger.info("Running autorun scripts terminated.");
291
                application.message("", JOptionPane.INFORMATION_MESSAGE);
292
                status.terminate();
293
                composer_initialized = true;
294
            }
295
        }
296
    }
297
    
298
    @Override
299
    public void initialize() {
300
        IconThemeHelper.registerIcon("action", "tools-scripting-launcher", this);
301
        IconThemeHelper.registerIcon("action", "tools-scripting-composer", this);
302
        IconThemeHelper.registerIcon("action", "tools-scripting-console-jython", this);
303
        this.message = new MessageWait();
304

    
305
        initPaths();
306
        Thread th = new Thread(new Runnable() {
307
            @Override
308
            public void run() {
309
                preloadPythonEngine();
310
            }
311
        }, "ScriptEnginesInitializer");
312
        th.start();
313
        try {
314
            th.join(3000); // force change to other thread
315
        } catch (InterruptedException ex) {
316
            // Ignore.
317
        }
318
    }
319

    
320
    private void preloadPythonEngine() {
321
        ScriptingManager manager = (ScriptingManager) ScriptingLocator.getManager();
322
        synchronized (manager) {
323
            String respath = "/scripting/langs/python/preload.py";
324
            InputStream res = this.getClass().getResourceAsStream(respath);
325
            if( res != null ) {
326
                logger.info("Scan for script engines");
327
                List<String> lines;
328
                try {
329
                    lines = IOUtils.readLines(res);
330
                    String code = StringUtils.join(lines, "\n");
331
                    logger.info("Preload python script engine");
332
                    Script script = manager.createScript(
333
                        "preload",
334
                        code,
335
                        ScriptingManager.PYTHON_LANGUAGE_NAME
336
                    );
337
                    logger.info("Preload python modules");
338
                    script.invokeFunction("main", null);
339

    
340
                } catch (Exception ex) {
341
                    logger.warn("Can't run preload script for python.", ex);
342
                }
343
                logger.info("Preload of script engines finished");
344
            }
345
        }
346
    }
347

    
348
    private File getScriptsHomeFolder() {
349
        PluginsManager pluginManager = PluginsLocator.getManager();
350
        File pluginHomeFolder = this.getPlugin().getPluginHomeFolder();
351

    
352
        File scriptsHomeFolder = null;
353
        File f = FileUtils.getFile(pluginHomeFolder, "scripts-folder.txt");
354
        if( f.exists() ) {
355
            try {
356
                List<String> lines = FileUtils.readLines(f);
357
                for( String line : lines ) {
358
                    line = line.trim();
359
                    if( !line.startsWith("#") ) {
360
                        scriptsHomeFolder = new File(line);
361
                        if( !scriptsHomeFolder.isAbsolute() ) {
362
                            scriptsHomeFolder = new File(pluginHomeFolder, line);
363
                        }
364
                        scriptsHomeFolder = new File(
365
                            FilenameUtils.normalizeNoEndSeparator(
366
                                scriptsHomeFolder.getAbsolutePath(),
367
                                true
368
                            )
369
                        );
370
                        if( scriptsHomeFolder.exists() ) {
371
                            return scriptsHomeFolder;
372
                        }
373
                    }
374
                }
375
            } catch (IOException ex) {
376
            }
377
        } else {
378
            try {
379
                FileUtils.touch(f);
380
            } catch (IOException ex) {
381
            }
382
        }
383
        String gvsigversion = pluginManager.getApplicationVersion().format("%M.%m.0") ;
384
        scriptsHomeFolder = FileUtils.getFile(pluginHomeFolder, gvsigversion) ;
385
        return scriptsHomeFolder;
386
    }
387
    
388
    private void initPaths() {
389
        PluginsManager pluginManager = PluginsLocator.getManager();
390

    
391
        ScriptingManager manager = ScriptingLocator.getManager();
392
        manager.setHomeFolder(getScriptsHomeFolder());
393

    
394
        ScriptingFolder folder = manager.createLink(
395
            "Common",
396
            manager.getUserFolder(), 
397
            "../../scripts"
398
        );
399
        folder.setProperty(SKIP_AUTORUNS, BooleanUtils.toStringTrueFalse(true));
400
        folder.save();
401
//        manager.createLink(
402
//            "Previous version",
403
//            manager.getUserFolder(), 
404
//            "../../../org.gvsig.scripting.app.extension/scripts"
405
//        );
406

    
407
        List<File> pluginsFolders = new ArrayList<>();
408
        for( File f : pluginManager.getPluginsFolders() ) {
409
            pluginsFolders.addAll(Arrays.asList(f.listFiles()));
410
        }
411

    
412
        for( File pluginFolder : pluginsFolders ) {
413
            File scriptsFolder = new File(pluginFolder, "scripting/scripts");
414
            if( scriptsFolder.exists() ) {
415
                manager.registerSystemFolder(pluginFolder.getName(), scriptsFolder);
416
            }
417
            File libFolder = new File(pluginFolder, "scripting/lib");
418
            if( libFolder.exists() ) {
419
                manager.addLibFolder(libFolder);
420
            }
421
        }
422
        manager.setPackagesFolder(pluginManager.getInstallFolder());
423

    
424
        File localAddonRepositoryFolder = new File(manager.getRootUserFolder(), "addons");
425
        if( !localAddonRepositoryFolder.exists() ) {
426
            try {
427
                FileUtils.forceMkdir(localAddonRepositoryFolder);
428
            } catch (IOException ex) {
429
                logger.info("Can't create addons folder in '" + localAddonRepositoryFolder.getAbsolutePath() + "'.", ex);
430
            }
431
        }
432
        File initAddonFile = new File(localAddonRepositoryFolder, "__init__.py");
433
        if( !initAddonFile.exists() ) {
434
            try {
435
                FileUtils.touch(initAddonFile);
436
            } catch (IOException ex) {
437
                logger.info("Can't create addons __init__ file in '" + localAddonRepositoryFolder.getAbsolutePath() + "'.", ex);
438
            }
439
        }
440
    }
441

    
442
    @Override
443
    public void postInitialize() {
444
        super.postInitialize();
445
        PluginsManager pluginManager = PluginsLocator.getManager();
446
        pluginManager.addStartupTask(
447
            "ExecuteAutorunScripts",
448
            new ExecuteAutorunScriptsOnStartup(),
449
            true,
450
            600
451
        );
452

    
453
        Invocable initializer = new ScriptsInstallerInitializer();
454
        initializer.call(this.getPlugin().getPluginName());
455
    }
456

    
457
    @Override
458
    public boolean isEnabled() {
459
        return true;
460
    }
461

    
462
    @Override
463
    public boolean isVisible() {
464
        return true;
465
    }
466

    
467
    private class ExecuteAutorunScriptsOnStartup implements Runnable {
468

    
469
        @Override
470
        public void run() {
471
            Thread th = new Thread(new ExecuteAutorunScripts());
472
            th.start();
473
        }
474
    }
475

    
476
    private class ExecuteAutorunScripts implements Runnable {
477

    
478
        @Override
479
        public void run() {
480
            final ApplicationManager application = ApplicationLocator.getManager();
481
            executingAutorunScripts = true;
482
            try {
483
                final ScriptingManager manager = ScriptingLocator.getManager();
484
                manager.loadEngines();
485

    
486
                final PluginsManager pluginManager = PluginsLocator.getManager();
487
                final I18nManager i18nManager = ToolsLocator.getI18nManager();
488

    
489
                final List<ScriptingBaseScript> autoruns = new ArrayList<>();
490

    
491
                List<File> pluginsFolders = new ArrayList<>();
492
                for( File f : pluginManager.getPluginsFolders() ) {
493
                    pluginsFolders.addAll(Arrays.asList(f.listFiles()));
494
                }
495

    
496
                application.message(
497
                    i18nManager.getTranslation("_Searching_autorun_scripts_Xhorizontal_ellipsisX"),
498
                    JOptionPane.INFORMATION_MESSAGE
499
                );
500
                for( File pluginFolder : pluginsFolders ) {
501
                    File autorun_file = new File(pluginFolder, "scripting/scripts/autorun.inf");
502
                    if( autorun_file.exists() ) {
503
                        ScriptingBaseScript autorun = manager.getScript(autorun_file);
504
                        if( autorun.isEnabled() ) {
505
                            autoruns.add(autorun);
506
                        } else {
507
                            logger.info("Skip autorun script '" + autorun_file.getAbsolutePath() + "'.");
508
                        }
509
                    }
510
                }
511

    
512
                SimpleFileVisitor<Path> visitor = new SimpleFileVisitor<Path>() {
513
                    @Override
514
                    public FileVisitResult visitFile(Path path, BasicFileAttributes bfa) throws IOException {
515
                        File file = path.toFile();
516
                        if( "autorun.inf".equalsIgnoreCase(file.getName()) ) {
517
                            if( file.exists() ) {
518
                                ScriptingBaseScript autorun = manager.getScript(file);
519
                                if( autorun.isEnabled() ) {
520
                                    autoruns.add(autorun);
521
                                } else {
522
                                    logger.info("Skip autorun script '" + file.getAbsolutePath() + "'.");
523
                                }
524
                            }
525
                        }
526
                        return FileVisitResult.CONTINUE;
527
                    }
528
                };
529
                try {
530
                    EnumSet<FileVisitOption> opts = EnumSet.of(FOLLOW_LINKS);
531
                    Files.walkFileTree(Paths.get(manager.getRootUserFolder().toURI()), opts, Integer.MAX_VALUE, visitor);
532
                    List<ScriptingFolder> folders = manager.getAlternativeUserFolders();
533
                    for( ScriptingFolder folder : folders ) {
534
                        Files.walkFileTree(Paths.get(folder.getFile().toURI()), opts, Integer.MAX_VALUE, visitor);
535
                    }
536
                } catch (Exception ex) {
537
                    logger.warn("Can't execute autoruns in home.", ex);
538
                }
539

    
540
                Collections.sort(autoruns, new Comparator<ScriptingBaseScript>() {
541

    
542
                    @Override
543
                    public int compare(ScriptingBaseScript o1, ScriptingBaseScript o2) {
544
                        return getScriptOrderKey(o2).compareToIgnoreCase(getScriptOrderKey(o1));
545
                    }
546
                });
547

    
548
                for( ScriptingBaseScript autorun : autoruns ) {
549
                    try {
550
                        logger.info("running autorun script '" + autorun.getFile().getAbsolutePath() + "' (" + getScriptOrderKey(autorun) + ", " + autorun.getIsolationGroup() + ").");
551
                        application.message(
552
                            i18nManager.getTranslation(
553
                                "_Running_autorun_script_from_XnameX",
554
                                new String[]{
555
                                        autorun.getFile().getParentFile().getName()}
556
                            ),
557
                            JOptionPane.INFORMATION_MESSAGE
558
                        );
559
                    } catch (Exception ex) {
560
                        // Ignore it
561
                    }
562
                    try {
563
                        autorun.run();
564
                    } catch (Exception ex) {
565
                        logger.warn("Can't execute autorun from '" + autorun.getFile().getAbsolutePath() + "'.", ex);
566
                    }
567
                }
568

    
569
            } finally {
570
                logger.info("Running autorun scripts terminated.");
571
                application.message("", JOptionPane.INFORMATION_MESSAGE);
572
                executingAutorunScripts = false;
573
            }
574
        }
575

    
576
        private String getScriptOrderKey(ScriptingBaseScript o) {
577
            int groupOrder = 500;
578
            String groupName = "default";
579
            int scriptOrder = 500;
580
            String s = o.getProperty("autorun.group.order");
581
            if( s != null ) {
582
                try {
583
                    groupOrder = Integer.parseInt(s);
584
                } catch (Exception ex) {
585
                    // Do nothing.
586
                }
587
            }
588
            s = o.getProperty("autorun.group.name");
589
            if( s != null ) {
590
                groupName = s;
591
            }
592
            s = o.getProperty("autorun.order");
593
            if( s != null ) {
594
                try {
595
                    scriptOrder = Integer.parseInt(s);
596
                } catch (Exception ex) {
597
                    // Do nothing.
598
                }
599
            }
600
            String key = MessageFormat.format(
601
                "{0,number,000000}.{1}.{2,number,000000}",
602
                groupOrder,
603
                groupName,
604
                scriptOrder
605
            );
606
            return key;
607
        }
608
    }
609
}