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

History | View | Annotate | Download (22.7 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

    
43
import javax.swing.JOptionPane;
44
import javax.swing.SwingUtilities;
45
import org.apache.commons.io.FileUtils;
46
import org.apache.commons.io.IOUtils;
47
import org.apache.commons.lang3.StringUtils;
48

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

    
82
public class ScriptingExtension extends Extension {
83

    
84
    private static final Logger logger = LoggerFactory.getLogger(ScriptingExtension.class);
85

    
86
    private PluginServices plugin = null;
87

    
88
    /*
89
     * la funcion log y las constantes estan pensadas para usarlas desde los scripts.
90
     */
91
    public static final int INFO = 0;
92
    public static final int TRACE = 1;
93
    public static final int WARN = 2;
94
    public static final int ERROR = 3;
95
    private static boolean composer_initialized = false;
96
    private boolean executingAutorunScripts = true;
97
    private MessageWait message;
98

    
99
    public static void log(String message) {
100
        log(INFO, message, null);
101
    }
102

    
103
    public static void log(int level, String message) {
104
        log(level, message, null);
105
    }
106

    
107
    public static void log(int level, String message, Throwable th) {
108
        switch( level ) {
109
        case TRACE:
110
            logger.trace(message, th);
111
            break;
112
        case ERROR:
113
            logger.error(message, th);
114
            break;
115
        case WARN:
116
            logger.warn(message, th);
117
            break;
118
        default:
119
        case INFO:
120
            logger.info(message, th);
121
            break;
122
        }
123
    }
124

    
125
    @Override
126
    public PluginServices getPlugin() {
127
        if( this.plugin == null ) {
128
            this.plugin = PluginsLocator.getManager().getPlugin(ScriptingExtension.class);
129
        }
130
        return this.plugin;
131
    }
132

    
133
    @Override
134
    public void execute(String actionCommand) {
135
        this.execute(actionCommand, null);
136
    }
137

    
138
    @Override
139
    public void execute(String command, Object[] args) {
140
        ScriptingUIManager uimanager = ScriptingSwingLocator.getUIManager();
141
        WindowManager winmanager = ToolsSwingLocator.getWindowManager();
142

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

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

    
178

    
179
        } else {
180
            ScriptingBaseScript script = uimanager.getManager().getScript(command);
181
            if( script != null ) {
182
                script.run(args);
183
            } else {
184
                ApplicationManager application = ApplicationLocator.getManager();
185
                application.messageDialog(
186
                        "Can't locate script '" + command + "'.", 
187
                        "ScriptLaunch", 
188
                        JOptionPane.OK_OPTION
189
                );
190
            }
191
        }
192
    }
193

    
194
    private void showScriptingComposer() {
195
        ScriptingUIManager uimanager = ScriptingSwingLocator.getUIManager();
196
        WindowManager winmanager = ToolsSwingLocator.getWindowManager();
197

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

    
212
    private class StartupScriptingComposer implements Runnable {
213

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

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

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

    
326
                } catch (Exception ex) {
327
                    logger.warn("Can't run preload script for python.", ex);
328
                }
329
                logger.info("Preload of script engines finished");
330
            }
331
        }
332
    }
333

    
334
    private void createLink(String name, File link, String targetPathName) {
335
        StringBuilder contents = new StringBuilder();
336
        
337
        contents.append("[Unit]\n")
338
            .append("type = Folder\n")
339
            .append("name = ").append(name).append("\n")
340
            .append("description =\n")
341
            .append("createdBy =\n")
342
            .append("version =\n")
343
            .append("\n")
344
            .append("[Folder]\n")
345
            .append("path =").append(targetPathName).append("\n")
346
            .append("\n\n");
347
        if( link.isDirectory() ) {
348
            link = new File(link,name+".inf");
349
        } else if( !link.getName().endsWith(".inf") ) {
350
            link = new File( link.getPath() + ".inf");
351
        }
352
        if( !link.exists() ) {
353
            try {
354
                FileUtils.writeStringToFile(link, contents.toString());
355
            } catch (IOException ex) {
356
                logger.warn("Can't create ScriptingFolder file in '" + link.getAbsolutePath() + "'.", ex);
357
            }
358
        }
359
    }
360

    
361
    private void initPaths() {
362
        ScriptingManager manager = ScriptingLocator.getManager();
363
        PluginsManager pluginManager = PluginsLocator.getManager();
364

    
365
        String gvsigversion = pluginManager.getApplicationVersion().format("%M.%m.%r");
366
        File home = FileUtils.getFile(this.getPlugin().getPluginHomeFolder(), gvsigversion);
367

    
368
        manager.setHomeFolder(home);
369

    
370
        this.createLink(
371
            "Previous version", 
372
            manager.getUserFolder().getFile(), 
373
            "../../org.gvsig.scripting.app.extension/scripts"
374
        );
375

    
376
        List<File> pluginsFolders = new ArrayList<>();
377
        for( File f : pluginManager.getPluginsFolders() ) {
378
            pluginsFolders.addAll(Arrays.asList(f.listFiles()));
379
        }
380

    
381
        for( File pluginFolder : pluginsFolders ) {
382
            File scriptsFolder = new File(pluginFolder, "scripting/scripts");
383
            if( scriptsFolder.exists() ) {
384
                manager.registerSystemFolder(pluginFolder.getName(), scriptsFolder);
385
            }
386
            File libFolder = new File(pluginFolder, "scripting/lib");
387
            if( libFolder.exists() ) {
388
                manager.addLibFolder(libFolder);
389
            }
390
        }
391
        manager.setPackagesFolder(pluginManager.getInstallFolder());
392

    
393
        File localAddonRepositoryFolder = new File(manager.getRootUserFolder(), "addons");
394
        if( !localAddonRepositoryFolder.exists() ) {
395
            try {
396
                FileUtils.forceMkdir(localAddonRepositoryFolder);
397
            } catch (IOException ex) {
398
                logger.info("Can't create addons folder in '" + localAddonRepositoryFolder.getAbsolutePath() + "'.", ex);
399
            }
400
        }
401
        File initAddonFile = new File(localAddonRepositoryFolder, "__init__.py");
402
        if( !initAddonFile.exists() ) {
403
            try {
404
                FileUtils.touch(initAddonFile);
405
            } catch (IOException ex) {
406
                logger.info("Can't create addons __init__ file in '" + localAddonRepositoryFolder.getAbsolutePath() + "'.", ex);
407
            }
408
        }
409
    }
410

    
411
    @Override
412
    public void postInitialize() {
413
        super.postInitialize();
414
        PluginsManager pluginManager = PluginsLocator.getManager();
415
        pluginManager.addStartupTask(
416
            "ExecuteAutorunScripts",
417
            new ExecuteAutorunScriptsOnStartup(),
418
            true,
419
            600
420
        );
421

    
422
        Invocable initializer = new ScriptsInstallerInitializer();
423
        initializer.call(this.getPlugin().getPluginName());
424
    }
425

    
426
    @Override
427
    public boolean isEnabled() {
428
        return true;
429
    }
430

    
431
    @Override
432
    public boolean isVisible() {
433
        return true;
434
    }
435

    
436
    private class ExecuteAutorunScriptsOnStartup implements Runnable {
437

    
438
        @Override
439
        public void run() {
440
            Thread th = new Thread(new ExecuteAutorunScripts());
441
            th.start();
442
        }
443
    }
444

    
445
    private class ExecuteAutorunScripts implements Runnable {
446

    
447
        @Override
448
        public void run() {
449
            final ApplicationManager application = ApplicationLocator.getManager();
450
            executingAutorunScripts = true;
451
            try {
452
                final ScriptingManager manager = ScriptingLocator.getManager();
453
                manager.loadEngines();
454

    
455
                final PluginsManager pluginManager = PluginsLocator.getManager();
456
                final I18nManager i18nManager = ToolsLocator.getI18nManager();
457

    
458
                final List<ScriptingBaseScript> autoruns = new ArrayList<>();
459

    
460
                List<File> pluginsFolders = new ArrayList<>();
461
                for( File f : pluginManager.getPluginsFolders() ) {
462
                    pluginsFolders.addAll(Arrays.asList(f.listFiles()));
463
                }
464

    
465
                application.message(
466
                    i18nManager.getTranslation("_Searching_autorun_scripts_Xhorizontal_ellipsisX"),
467
                    JOptionPane.INFORMATION_MESSAGE
468
                );
469
                for( File pluginFolder : pluginsFolders ) {
470
                    File autorun_file = new File(pluginFolder, "scripting/scripts/autorun.inf");
471
                    if( autorun_file.exists() ) {
472
                        ScriptingBaseScript autorun = manager.getScript(autorun_file);
473
                        if( autorun.isEnabled() ) {
474
                            autoruns.add(autorun);
475
                        } else {
476
                            logger.info("Skip autorun script '" + autorun_file.getAbsolutePath() + "'.");
477
                        }
478
                    }
479
                }
480

    
481
                SimpleFileVisitor<Path> visitor = new SimpleFileVisitor<Path>() {
482
                    @Override
483
                    public FileVisitResult visitFile(Path path, BasicFileAttributes bfa) throws IOException {
484
                        File file = path.toFile();
485
                        if( "autorun.inf".equalsIgnoreCase(file.getName()) ) {
486
                            if( file.exists() ) {
487
                                ScriptingBaseScript autorun = manager.getScript(file);
488
                                if( autorun.isEnabled() ) {
489
                                    autoruns.add(autorun);
490
                                } else {
491
                                    logger.info("Skip autorun script '" + file.getAbsolutePath() + "'.");
492
                                }
493
                            }
494
                        }
495
                        return FileVisitResult.CONTINUE;
496
                    }
497
                };
498
                try {
499
                    EnumSet<FileVisitOption> opts = EnumSet.of(FOLLOW_LINKS);
500
                    Files.walkFileTree(Paths.get(manager.getRootUserFolder().toURI()), opts, Integer.MAX_VALUE, visitor);
501
                    List<ScriptingFolder> folders = manager.getAlternativeUserFolders();
502
                    for( ScriptingFolder folder : folders ) {
503
                        Files.walkFileTree(Paths.get(folder.getFile().toURI()), opts, Integer.MAX_VALUE, visitor);
504
                    }
505
                } catch (Exception ex) {
506
                    logger.warn("Can't execute autoruns in home.", ex);
507
                }
508

    
509
                Collections.sort(autoruns, new Comparator<ScriptingBaseScript>() {
510

    
511
                    @Override
512
                    public int compare(ScriptingBaseScript o1, ScriptingBaseScript o2) {
513
                        return getScriptOrderKey(o2).compareToIgnoreCase(getScriptOrderKey(o1));
514
                    }
515
                });
516

    
517
                for( ScriptingBaseScript autorun : autoruns ) {
518
                    try {
519
                        logger.info("running autorun script '" + autorun.getFile().getAbsolutePath() + "' (" + getScriptOrderKey(autorun) + ", " + autorun.getIsolationGroup() + ").");
520
                        application.message(
521
                            i18nManager.getTranslation(
522
                                "_Running_autorun_script_from_XnameX",
523
                                new String[]{
524
                                        autorun.getFile().getParentFile().getName()}
525
                            ),
526
                            JOptionPane.INFORMATION_MESSAGE
527
                        );
528
                    } catch (Exception ex) {
529
                        // Ignore it
530
                    }
531
                    try {
532
                        autorun.run();
533
                    } catch (Exception ex) {
534
                        logger.warn("Can't execute autorun from '" + autorun.getFile().getAbsolutePath() + "'.", ex);
535
                    }
536
                }
537

    
538
            } finally {
539
                logger.info("Running autorun scripts terminated.");
540
                application.message("", JOptionPane.INFORMATION_MESSAGE);
541
                executingAutorunScripts = false;
542
            }
543
        }
544

    
545
        private String getScriptOrderKey(ScriptingBaseScript o) {
546
            int groupOrder = 500;
547
            String groupName = "default";
548
            int scriptOrder = 500;
549
            String s = o.getProperty("autorun.group.order");
550
            if( s != null ) {
551
                try {
552
                    groupOrder = Integer.parseInt(s);
553
                } catch (Exception ex) {
554
                    // Do nothing.
555
                }
556
            }
557
            s = o.getProperty("autorun.group.name");
558
            if( s != null ) {
559
                groupName = s;
560
            }
561
            s = o.getProperty("autorun.order");
562
            if( s != null ) {
563
                try {
564
                    scriptOrder = Integer.parseInt(s);
565
                } catch (Exception ex) {
566
                    // Do nothing.
567
                }
568
            }
569
            String key = MessageFormat.format(
570
                "{0,number,000000}.{1}.{2,number,000000}",
571
                groupOrder,
572
                groupName,
573
                scriptOrder
574
            );
575
            return key;
576
        }
577
    }
578
}