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

History | View | Annotate | Download (21.1 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.swing.api.JScriptingComposer;
63
import org.gvsig.scripting.swing.api.ScriptingSwingLocator;
64
import org.gvsig.scripting.swing.api.ScriptingUIManager;
65
import static org.gvsig.scripting.swing.api.ScriptingUIManager.SCRIPT_COMPOSER_AUTORUN;
66
import org.gvsig.tools.dynobject.DynObject;
67
import org.gvsig.tools.swing.api.ToolsSwingLocator;
68
import org.gvsig.tools.swing.api.windowmanager.WindowManager;
69
import org.gvsig.tools.swing.impl.windowmanager.DefaultWindowManager;
70
import org.slf4j.Logger;
71
import org.slf4j.LoggerFactory;
72
import org.gvsig.tools.ToolsLocator;
73
import org.gvsig.tools.exception.BaseException;
74
import org.gvsig.tools.i18n.I18nManager;
75
import org.gvsig.tools.script.Script;
76
import org.gvsig.tools.task.SimpleTaskStatus;
77
import org.gvsig.tools.util.Invocable;
78
import org.gvsig.tools.visitor.VisitCanceledException;
79
import org.gvsig.tools.visitor.Visitor;
80

    
81
public class ScriptingExtension extends Extension {
82

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

    
85
    private PluginServices plugin = null;
86

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

    
96
    public static void log(String message) {
97
        log(INFO, message, null);
98
    }
99

    
100
    public static void log(int level, String message) {
101
        log(level, message, null);
102
    }
103

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

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

    
130
    @Override
131
    public void execute(String actionCommand) {
132
        this.execute(actionCommand, null);
133
    }
134

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

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

    
143
        } else if( "tools-scripting-composer".equalsIgnoreCase(command) ) {
144
            if( composer_initialized ) {
145
                showScriptingComposer();
146
            } else {
147
                Thread th = new Thread(new StartupAndShowScriptingComposer(), "StartupAndShowScriptingComposer");
148
                th.start();
149
            }
150

    
151
        } else {
152
            ScriptingBaseScript script = uimanager.getManager().getScript(command);
153
            if( script != null ) {
154
                script.run(args);
155
            } else {
156
                ApplicationManager application = ApplicationLocator.getManager();
157
                application.messageDialog("Can't locate script '" + command + "'.", "ScriptLaunch", JOptionPane.OK_OPTION);
158
            }
159
        }
160
    }
161

    
162
    private void showScriptingComposer() {
163
        ScriptingUIManager uimanager = ScriptingSwingLocator.getUIManager();
164
        WindowManager winmanager = ToolsSwingLocator.getWindowManager();
165

    
166
        DynObject preferences = getPlugin().getPluginProperties();
167
        Boolean composerUseHisWindowManager = (Boolean) preferences.getDynValue("ComposerUseHisWindowManager");
168
        ScriptingUIManager uiManager = ScriptingSwingLocator.getUIManager();
169
        if( composerUseHisWindowManager ) {
170
            winmanager = new DefaultWindowManager();
171
            uiManager.setWindowManager(winmanager);
172
        }
173
        JScriptingComposer composer = uimanager.createComposer();
174
        uiManager.showWindow(
175
            composer.asJComponent(),
176
            uimanager.getTranslation("Scripting_Composer")
177
        );
178
    }
179

    
180
    private class StartupAndShowScriptingComposer implements Runnable {
181

    
182
        @Override
183
        public void run() {
184
            SimpleTaskStatus status = ToolsLocator.getTaskStatusManager().createDefaultSimpleTaskStatus("Script composer startup");
185
            status.setIndeterminate();
186
            status.setAutoremove(true);
187
            status.add();
188
            final ApplicationManager application = ApplicationLocator.getManager();
189
            final I18nManager i18nManager = ToolsLocator.getI18nManager();            
190
            try {
191
                logger.info("Searching autorun scripts...");
192
                application.message(
193
                    i18nManager.getTranslation("_Searching_autorun_scripts_Xhorizontal_ellipsisX"),
194
                    JOptionPane.INFORMATION_MESSAGE
195
                );
196
                ScriptingManager manager = ScriptingLocator.getManager();
197
                final List<ScriptingScript> autoruns = new ArrayList<>();
198
                
199
                Visitor visitor = new Visitor() {
200
                    
201
                    @Override
202
                    public void visit(Object o) throws VisitCanceledException, BaseException {
203
                        ScriptingUnit unit = (ScriptingUnit) o;
204
                        if( unit instanceof ScriptingScript && SCRIPT_COMPOSER_AUTORUN.equalsIgnoreCase(unit.getId()) ) {
205
                            ScriptingScript autorun = (ScriptingScript) unit;
206
                            if( autorun.isEnabled() ) {
207
                                autoruns.add(autorun);
208
                            } else {
209
                                logger.info("Skip scautorun script '" + autorun.getFile().getAbsolutePath() + "'.");
210
                            }
211
                        }
212
                    }
213
                };
214
                manager.getSystemFolder().accept(visitor);
215
                manager.getUserFolder().accept(visitor);
216
                if( !autoruns.isEmpty() ) {
217
                    status.setRangeOfValues(0, autoruns.size());
218
                    int n=0;
219
                    for (ScriptingScript autorun : autoruns) {
220
                        status.setCurValue(n++);
221
                        try {
222
                            logger.info("running autorun script '" + autorun.getFile().getAbsolutePath() + ".");
223
                            application.message(
224
                                i18nManager.getTranslation(
225
                                    "_Running_autorun_script_from_XnameX",
226
                                    new String[]{
227
                                            autorun.getFile().getParentFile().getName()}
228
                                ),
229
                                JOptionPane.INFORMATION_MESSAGE
230
                            );
231
                        } catch (Exception ex) {
232
                            // Ignore it
233
                        }
234
                        try {
235
                            autorun.run();
236
                        } catch (Exception ex) {
237
                            logger.warn("Can't execute autorun from '" + autorun.getFile().getAbsolutePath() + "'.", ex);
238
                        }
239
                    }
240
                }
241
            } catch(Throwable th) {
242
                
243
            } finally {
244
                logger.info("Running autorun scripts terminated.");
245
                application.message("", JOptionPane.INFORMATION_MESSAGE);
246
                status.terminate();
247
                composer_initialized = true;
248
            }
249
        
250
            SwingUtilities.invokeLater(new Runnable() {
251
                @Override
252
                public void run() {
253
                    showScriptingComposer();
254
                }
255
            });
256
        }
257
    }
258
    
259
    @Override
260
    public void initialize() {
261
        IconThemeHelper.registerIcon("action", "tools-scripting-launcher", this);
262
        IconThemeHelper.registerIcon("action", "tools-scripting-composer", this);
263
        IconThemeHelper.registerIcon("action", "tools-scripting-console-jython", this);
264

    
265
        initPaths();
266
        Thread th = new Thread(new Runnable() {
267
            @Override
268
            public void run() {
269
                preloadPythonEngine();
270
            }
271
        }, "ScriptEnginesInitializer");
272
        th.start();
273
        try {
274
            th.join(3000); // force change to other thread
275
        } catch (InterruptedException ex) {
276
            // Ignore.
277
        }
278
    }
279

    
280
    private void preloadPythonEngine() {
281
        ScriptingManager manager = (ScriptingManager) ScriptingLocator.getManager();
282
        synchronized (manager) {
283
            String respath = "/scripting/langs/python/preload.py";
284
            InputStream res = this.getClass().getResourceAsStream(respath);
285
            if( res != null ) {
286
                logger.info("Scan for script engines");
287
                List<String> lines;
288
                try {
289
                    lines = IOUtils.readLines(res);
290
                    String code = StringUtils.join(lines, "\n");
291
                    logger.info("Preload python script engine");
292
                    Script script = manager.createScript(
293
                        "preload",
294
                        code,
295
                        ScriptingManager.PYTHON_LANGUAGE_NAME
296
                    );
297
                    logger.info("Preload python modules");
298
                    script.invokeFunction("main", null);
299

    
300
                } catch (Exception ex) {
301
                    logger.warn("Can't run preload script for python.", ex);
302
                }
303
                logger.info("Preload of script engines finished");
304
            }
305
        }
306
    }
307

    
308
    private void addLinkToPreviousVersion(ScriptingManager manager) {
309

    
310
        String contents = "[Unit]\n"
311
            + "type = Folder\n"
312
            + "name = Previous version\n"
313
            + "description =\n"
314
            + "createdBy =\n"
315
            + "version =\n"
316
            + "\n"
317
            + "[Folder]\n"
318
            + "path = ../../org.gvsig.scripting.app.extension/scripts\n\n\n";
319
        File previousVersion = new File(manager.getUserFolder().getFile(), "previous_version.inf");
320
        if( !previousVersion.exists() ) {
321
            try {
322
                FileUtils.writeStringToFile(previousVersion, contents);
323
            } catch (IOException ex) {
324
                logger.warn("Can't create ScriptingFolder file in '" + previousVersion.getAbsolutePath() + "'.", ex);
325
            }
326
        }
327
    }
328

    
329
    private void initPaths() {
330
        ScriptingManager manager = ScriptingLocator.getManager();
331
        PluginsManager pluginManager = PluginsLocator.getManager();
332

    
333
        File home = this.getPlugin().getPluginHomeFolder();
334
        manager.setHomeFolder(home);
335

    
336
        this.addLinkToPreviousVersion(manager);
337

    
338
        List<File> pluginsFolders = new ArrayList<>();
339
        for( File f : pluginManager.getPluginsFolders() ) {
340
            pluginsFolders.addAll(Arrays.asList(f.listFiles()));
341
        }
342

    
343
        for( File pluginFolder : pluginsFolders ) {
344
            File scriptsFolder = new File(pluginFolder, "scripting/scripts");
345
            if( scriptsFolder.exists() ) {
346
                manager.registerSystemFolder(pluginFolder.getName(), scriptsFolder);
347
            }
348
            File libFolder = new File(pluginFolder, "scripting/lib");
349
            if( libFolder.exists() ) {
350
                manager.addLibFolder(libFolder);
351
            }
352
        }
353
        manager.setPackagesFolder(pluginManager.getInstallFolder());
354

    
355
        File localAddonRepositoryFolder = new File(manager.getRootUserFolder(), "addons");
356
        if( !localAddonRepositoryFolder.exists() ) {
357
            try {
358
                FileUtils.forceMkdir(localAddonRepositoryFolder);
359
            } catch (IOException ex) {
360
                logger.info("Can't create addons folder in '" + localAddonRepositoryFolder.getAbsolutePath() + "'.", ex);
361
            }
362
        }
363
        File initAddonFile = new File(localAddonRepositoryFolder, "__init__.py");
364
        if( !initAddonFile.exists() ) {
365
            try {
366
                FileUtils.touch(initAddonFile);
367
            } catch (IOException ex) {
368
                logger.info("Can't create addons __init__ file in '" + localAddonRepositoryFolder.getAbsolutePath() + "'.", ex);
369
            }
370
        }
371
    }
372

    
373
    @Override
374
    public void postInitialize() {
375
        super.postInitialize();
376
        PluginsManager pluginManager = PluginsLocator.getManager();
377
        pluginManager.addStartupTask(
378
            "ExecuteAutorunScripts",
379
            new ExecuteAutorunScriptsOnStartup(),
380
            true,
381
            600
382
        );
383

    
384
        Invocable initializer = new ScriptsInstallerInitializer();
385
        initializer.call(this.getPlugin().getPluginName());
386
    }
387

    
388
    @Override
389
    public boolean isEnabled() {
390
        return true;
391
    }
392

    
393
    @Override
394
    public boolean isVisible() {
395
        return true;
396
    }
397

    
398
    private static class ExecuteAutorunScriptsOnStartup implements Runnable {
399

    
400
        @Override
401
        public void run() {
402
            Thread th = new Thread(new ExecuteAutorunScripts());
403
            th.start();
404
        }
405
    }
406

    
407
    private static class ExecuteAutorunScripts implements Runnable {
408

    
409
        @Override
410
        public void run() {
411
            final ScriptingManager manager = ScriptingLocator.getManager();
412
            manager.loadEngines();
413

    
414
            final PluginsManager pluginManager = PluginsLocator.getManager();
415
            final ApplicationManager application = ApplicationLocator.getManager();
416
            final I18nManager i18nManager = ToolsLocator.getI18nManager();
417

    
418
            final List<ScriptingBaseScript> autoruns = new ArrayList<>();
419

    
420
            try {
421
                List<File> pluginsFolders = new ArrayList<>();
422
                for( File f : pluginManager.getPluginsFolders() ) {
423
                    pluginsFolders.addAll(Arrays.asList(f.listFiles()));
424
                }
425

    
426
                application.message(
427
                    i18nManager.getTranslation("_Searching_autorun_scripts_Xhorizontal_ellipsisX"),
428
                    JOptionPane.INFORMATION_MESSAGE
429
                );
430
                for( File pluginFolder : pluginsFolders ) {
431
                    File autorun_file = new File(pluginFolder, "scripting/scripts/autorun.inf");
432
                    if( autorun_file.exists() ) {
433
                        ScriptingBaseScript autorun = manager.getScript(autorun_file);
434
                        if( autorun.isEnabled() ) {
435
                            autoruns.add(autorun);
436
                        } else {
437
                            logger.info("Skip autorun script '" + autorun_file.getAbsolutePath() + "'.");
438
                        }
439
                    }
440
                }
441

    
442
                SimpleFileVisitor<Path> visitor = new SimpleFileVisitor<Path>() {
443
                    @Override
444
                    public FileVisitResult visitFile(Path path, BasicFileAttributes bfa) throws IOException {
445
                        File file = path.toFile();
446
                        if( "autorun.inf".equalsIgnoreCase(file.getName()) ) {
447
                            if( file.exists() ) {
448
                                ScriptingBaseScript autorun = manager.getScript(file);
449
                                if( autorun.isEnabled() ) {
450
                                    autoruns.add(autorun);
451
                                } else {
452
                                    logger.info("Skip autorun script '" + file.getAbsolutePath() + "'.");
453
                                }
454
                            }
455
                        }
456
                        return FileVisitResult.CONTINUE;
457
                    }
458
                };
459
                try {
460
                    EnumSet<FileVisitOption> opts = EnumSet.of(FOLLOW_LINKS);
461
                    Files.walkFileTree(Paths.get(manager.getRootUserFolder().toURI()), opts, Integer.MAX_VALUE, visitor);
462
                    List<ScriptingFolder> folders = manager.getAlternativeUserFolders();
463
                    for( ScriptingFolder folder : folders ) {
464
                        Files.walkFileTree(Paths.get(folder.getFile().toURI()), opts, Integer.MAX_VALUE, visitor);
465
                    }
466
                } catch (Exception ex) {
467
                    logger.warn("Can't execute autoruns in home.", ex);
468
                }
469

    
470
                Collections.sort(autoruns, new Comparator<ScriptingBaseScript>() {
471

    
472
                    @Override
473
                    public int compare(ScriptingBaseScript o1, ScriptingBaseScript o2) {
474
                        return getScriptOrderKey(o2).compareToIgnoreCase(getScriptOrderKey(o1));
475
                    }
476
                });
477

    
478
                for( ScriptingBaseScript autorun : autoruns ) {
479
                    try {
480
                        logger.info("running autorun script '" + autorun.getFile().getAbsolutePath() + "' (" + getScriptOrderKey(autorun) + ", " + autorun.getIsolationGroup() + ").");
481
                        application.message(
482
                            i18nManager.getTranslation(
483
                                "_Running_autorun_script_from_XnameX",
484
                                new String[]{
485
                                        autorun.getFile().getParentFile().getName()}
486
                            ),
487
                            JOptionPane.INFORMATION_MESSAGE
488
                        );
489
                    } catch (Exception ex) {
490
                        // Ignore it
491
                    }
492
                    try {
493
                        autorun.run();
494
                    } catch (Exception ex) {
495
                        logger.warn("Can't execute autorun from '" + autorun.getFile().getAbsolutePath() + "'.", ex);
496
                    }
497
                }
498

    
499
            } finally {
500
                logger.info("Running autorun scripts terminated.");
501
                application.message("", JOptionPane.INFORMATION_MESSAGE);
502
            }
503
        }
504

    
505
        private String getScriptOrderKey(ScriptingBaseScript o) {
506
            int groupOrder = 500;
507
            String groupName = "default";
508
            int scriptOrder = 500;
509
            String s = o.getProperty("autorun.group.order");
510
            if( s != null ) {
511
                try {
512
                    groupOrder = Integer.parseInt(s);
513
                } catch (Exception ex) {
514
                    // Do nothing.
515
                }
516
            }
517
            s = o.getProperty("autorun.group.name");
518
            if( s != null ) {
519
                groupName = s;
520
            }
521
            s = o.getProperty("autorun.order");
522
            if( s != null ) {
523
                try {
524
                    scriptOrder = Integer.parseInt(s);
525
                } catch (Exception ex) {
526
                    // Do nothing.
527
                }
528
            }
529
            String key = MessageFormat.format(
530
                "{0,number,000000}.{1}.{2,number,000000}",
531
                groupOrder,
532
                groupName,
533
                scriptOrder
534
            );
535
            return key;
536
        }
537
    }
538
}