Browse Source

DI the script plugin.

Change-Id: I6880a8ea1570e582929a8e277a727dfd20d3c8f7
Reviewed-on: http://gerrit.dmdirc.com/3188
Reviewed-by: Chris Smith <chris@dmdirc.com>
Automatic-Compile: DMDirc Build Manager
tags/0.8
Greg Holmes 10 years ago
parent
commit
ebf5c9abac

+ 69
- 71
src/com/dmdirc/addons/scriptplugin/ScriptCommand.java View File

@@ -22,7 +22,9 @@
22 22
 
23 23
 package com.dmdirc.addons.scriptplugin;
24 24
 
25
+import com.dmdirc.ClientModule.GlobalConfig;
25 26
 import com.dmdirc.FrameContainer;
27
+import com.dmdirc.commandline.CommandLineOptionsModule.Directory;
26 28
 import com.dmdirc.commandparser.BaseCommandInfo;
27 29
 import com.dmdirc.commandparser.CommandArguments;
28 30
 import com.dmdirc.commandparser.CommandInfo;
@@ -31,20 +33,17 @@ import com.dmdirc.commandparser.commands.Command;
31 33
 import com.dmdirc.commandparser.commands.IntelligentCommand;
32 34
 import com.dmdirc.commandparser.commands.context.CommandContext;
33 35
 import com.dmdirc.interfaces.CommandController;
34
-import com.dmdirc.interfaces.config.IdentityController;
35
-import com.dmdirc.plugins.PluginInfo;
36
+import com.dmdirc.interfaces.config.AggregateConfigProvider;
37
+import com.dmdirc.plugins.PluginDomain;
36 38
 import com.dmdirc.ui.input.AdditionalTabTargets;
37 39
 
38 40
 import java.io.File;
39 41
 import java.io.FileNotFoundException;
40 42
 import java.io.FileWriter;
41 43
 import java.io.IOException;
42
-import java.lang.reflect.Method;
43
-import java.util.Arrays;
44
-import java.util.LinkedList;
45
-import java.util.List;
46 44
 import java.util.Map;
47 45
 
46
+import javax.inject.Inject;
48 47
 import javax.script.ScriptEngineManager;
49 48
 import javax.script.ScriptException;
50 49
 
@@ -56,36 +55,40 @@ public class ScriptCommand extends Command implements IntelligentCommand {
56 55
     /** A command info object for this command. */
57 56
     public static final CommandInfo INFO = new BaseCommandInfo("script",
58 57
             "script - Allows controlling the script plugin", CommandType.TYPE_GLOBAL);
59
-    /** My Plugin. */
60
-    private final ScriptPlugin myPlugin;
61
-    /** The controller to read/write settings with. */
62
-    private final IdentityController identityController;
58
+    /** Global config to read settings from. */
59
+    private final AggregateConfigProvider globalConfig;
63 60
     /** Plugin settings domain. */
64 61
     private final String domain;
65 62
     /** Manager used to retrieve script engines. */
66 63
     private final ScriptEngineManager ScriptEngineManager;
67 64
     /** Script directory. */
68 65
     private final String scriptDirectory;
66
+    /** Script manager to handle scripts. */
67
+    private final ScriptManager scriptManager;
69 68
 
70 69
     /**
71 70
      * Creates a new instance of this command.
72 71
      *
73
-     * @param myPlugin           The plugin that owns the command.
74
-     * @param identityController The controller to read and write settings from.
75
-     * @param commandController  The controller to use for command information.
76
-     * @param pluginInfo         This plugin's info object
77
-     * @param scriptManager      Manager used to get script engines
78
-     * @param scriptDirectory    Directory to store scripts
72
+     * @param scriptManager       Used to manage scripts
73
+     * @param globalConfig        Global config
74
+     * @param commandController   The controller to use for command information.
75
+     * @param domain              This plugin's settings domain
76
+     * @param scriptEngineManager Manager used to get script engines
77
+     * @param scriptDirectory     Directory to store scripts
79 78
      */
80
-    public ScriptCommand(final ScriptPlugin myPlugin, final IdentityController identityController,
81
-            final CommandController commandController, final PluginInfo pluginInfo,
82
-            final ScriptEngineManager scriptManager, final String scriptDirectory) {
79
+    @Inject
80
+    public ScriptCommand(final ScriptManager scriptManager,
81
+            @Directory(ScriptModule.SCRIPTS) final String scriptDirectory,
82
+            @GlobalConfig final AggregateConfigProvider globalConfig,
83
+            final CommandController commandController,
84
+            @PluginDomain(ScriptPlugin.class) final String domain,
85
+            final ScriptEngineManager scriptEngineManager) {
83 86
         super(commandController);
84
-        this.myPlugin = myPlugin;
85
-        this.identityController = identityController;
86
-        this.domain = pluginInfo.getDomain();
87
-        this.ScriptEngineManager = scriptManager;
87
+        this.globalConfig = globalConfig;
88
+        this.domain = domain;
89
+        this.ScriptEngineManager = scriptEngineManager;
88 90
         this.scriptDirectory = scriptDirectory;
91
+        this.scriptManager = scriptManager;
89 92
     }
90 93
 
91 94
     /** {@inheritDoc} */
@@ -97,12 +100,12 @@ public class ScriptCommand extends Command implements IntelligentCommand {
97 100
         if (sargs.length > 0 && (sargs[0].equalsIgnoreCase("rehash") || sargs[0].equalsIgnoreCase(
98 101
                 "reload"))) {
99 102
             sendLine(origin, args.isSilent(), FORMAT_OUTPUT, "Reloading scripts");
100
-            myPlugin.rehash();
103
+            scriptManager.rehash();
101 104
         } else if (sargs.length > 0 && sargs[0].equalsIgnoreCase("load")) {
102 105
             if (sargs.length > 1) {
103 106
                 final String filename = args.getArgumentsAsString(1);
104 107
                 sendLine(origin, args.isSilent(), FORMAT_OUTPUT, "Loading: " + filename + " ["
105
-                        + myPlugin.loadScript(scriptDirectory + filename) + "]");
108
+                        + scriptManager.loadScript(scriptDirectory + filename) + "]");
106 109
             } else {
107 110
                 sendLine(origin, args.isSilent(), FORMAT_ERROR, "You must specify a script to load");
108 111
             }
@@ -110,7 +113,7 @@ public class ScriptCommand extends Command implements IntelligentCommand {
110 113
             if (sargs.length > 1) {
111 114
                 final String filename = args.getArgumentsAsString(1);
112 115
                 sendLine(origin, args.isSilent(), FORMAT_OUTPUT, "Unloading: " + filename + " ["
113
-                        + myPlugin.loadScript(scriptDirectory + filename) + "]");
116
+                        + scriptManager.loadScript(scriptDirectory + filename) + "]");
114 117
             } else {
115 118
                 sendLine(origin, args.isSilent(), FORMAT_ERROR,
116 119
                         "You must specify a script to unload");
@@ -121,10 +124,9 @@ public class ScriptCommand extends Command implements IntelligentCommand {
121 124
                 sendLine(origin, args.isSilent(), FORMAT_OUTPUT, "Evaluating: " + script);
122 125
                 try {
123 126
                     ScriptEngineWrapper wrapper;
124
-                    if (identityController.getGlobalConfiguration().hasOptionString(domain,
125
-                            "eval.baseFile")) {
126
-                        final String baseFile = scriptDirectory + '/' + identityController.
127
-                                getGlobalConfiguration().getOption(domain, "eval.baseFile");
127
+                    if (globalConfig.hasOptionString(domain, "eval.baseFile")) {
128
+                        final String baseFile = scriptDirectory + '/'
129
+                                + globalConfig.getOption(domain, "eval.baseFile");
128 130
                         if (new File(baseFile).exists()) {
129 131
                             wrapper = new ScriptEngineWrapper(ScriptEngineManager, baseFile);
130 132
                         } else {
@@ -142,26 +144,10 @@ public class ScriptCommand extends Command implements IntelligentCommand {
142 144
                     sendLine(origin, args.isSilent(), FORMAT_OUTPUT, "Exception: " + e + " -> " + e.
143 145
                             getMessage());
144 146
 
145
-                    if (identityController.getGlobalConfiguration().getOptionBool(domain,
146
-                            "eval.showStackTrace")) {
147
-                        try {
148
-                            final Class<?> logger = Class.forName("com.dmdirc.logger.Logger");
149
-                            if (logger != null) {
150
-                                final Method exceptionToStringArray = logger.getDeclaredMethod(
151
-                                        "exceptionToStringArray", new Class<?>[]{Throwable.class});
152
-                                exceptionToStringArray.setAccessible(true);
153
-
154
-                                final String[] stacktrace = (String[]) exceptionToStringArray.
155
-                                        invoke(null, e);
156
-                                for (String line : stacktrace) {
157
-                                    sendLine(origin, args.isSilent(), FORMAT_OUTPUT, "Stack trace: "
158
-                                            + line);
159
-                                }
160
-                            }
161
-                        } catch (ReflectiveOperationException ex) {
162
-                            sendLine(origin, args.isSilent(), FORMAT_OUTPUT,
163
-                                    "Stack trace: Exception showing stack trace: " + ex + " -> "
164
-                                    + ex.getMessage());
147
+                    if (globalConfig.getOptionBool(domain, "eval.showStackTrace")) {
148
+                        final String[] stacktrace = getTrace(e);
149
+                        for (String line : stacktrace) {
150
+                            sendLine(origin, args.isSilent(), FORMAT_OUTPUT, "Stack trace: " + line);
165 151
                         }
166 152
                     }
167 153
 
@@ -177,11 +163,10 @@ public class ScriptCommand extends Command implements IntelligentCommand {
177 163
                 final String script = args.getArgumentsAsString(2);
178 164
                 sendLine(origin, args.isSilent(), FORMAT_OUTPUT, "Saving as '" + functionName
179 165
                         + "': " + script);
180
-                if (identityController.getGlobalConfiguration().
181
-                        hasOptionString(domain, "eval.baseFile")) {
166
+                if (globalConfig.hasOptionString(domain, "eval.baseFile")) {
182 167
                     try {
183
-                        final String baseFile = scriptDirectory + '/' + identityController.
184
-                                getGlobalConfiguration().getOption(domain, "eval.baseFile");
168
+                        final String baseFile = scriptDirectory + '/'
169
+                                + globalConfig.getOption(domain, "eval.baseFile");
185 170
                         try (FileWriter writer = new FileWriter(baseFile, true)) {
186 171
                             writer.write("function ");
187 172
                             writer.write(functionName);
@@ -252,9 +237,9 @@ public class ScriptCommand extends Command implements IntelligentCommand {
252 237
             res.add("eval");
253 238
             res.add("savetobasefile");
254 239
         } else if (arg == 1) {
255
-            final Map<String, ScriptEngineWrapper> scripts = myPlugin.getScripts();
240
+            final Map<String, ScriptEngineWrapper> scripts = scriptManager.getScripts();
256 241
             if (context.getPreviousArgs().get(0).equalsIgnoreCase("load")) {
257
-                for (String filename : getPossibleScripts()) {
242
+                for (String filename : scriptManager.getPossibleScripts()) {
258 243
                     res.add(filename);
259 244
                 }
260 245
             } else if (context.getPreviousArgs().get(0).equalsIgnoreCase("unload")) {
@@ -268,27 +253,40 @@ public class ScriptCommand extends Command implements IntelligentCommand {
268 253
     }
269 254
 
270 255
     /**
271
-     * Retrieves a list of all installed scripts. Any file under the main plugin directory
272
-     * (~/.DMDirc/scripts or similar) that matches *.js is deemed to be a valid script.
256
+     * Converts an exception into a string array.
257
+     *
258
+     * @param throwable Exception to convert
273 259
      *
274
-     * @return A list of all installed scripts
260
+     * @return Exception string array
275 261
      */
276
-    private List<String> getPossibleScripts() {
277
-        final List<String> res = new LinkedList<>();
262
+    private static String[] getTrace(final Throwable throwable) {
263
+        String[] trace;
278 264
 
279
-        final LinkedList<File> dirs = new LinkedList<>();
280
-        dirs.add(new File(scriptDirectory));
265
+        if (throwable == null) {
266
+            trace = new String[0];
267
+        } else {
268
+            final StackTraceElement[] traceElements = throwable.getStackTrace();
269
+            trace = new String[traceElements.length + 1];
270
+
271
+            trace[0] = throwable.toString();
281 272
 
282
-        while (!dirs.isEmpty()) {
283
-            final File dir = dirs.pop();
284
-            if (dir.isDirectory()) {
285
-                dirs.addAll(Arrays.asList(dir.listFiles()));
286
-            } else if (dir.isFile() && dir.getName().endsWith(".js")) {
287
-                final String target = dir.getPath();
288
-                res.add(target.substring(scriptDirectory.length(), target.length()));
273
+            for (int i = 0; i < traceElements.length; i++) {
274
+                trace[i + 1] = traceElements[i].toString();
275
+            }
276
+
277
+            if (throwable.getCause() != null) {
278
+                final String[] causeTrace = getTrace(throwable.getCause());
279
+                final String[] newTrace = new String[trace.length + causeTrace.length];
280
+                trace[0] = "\nWhich caused: " + trace[0];
281
+
282
+                System.arraycopy(causeTrace, 0, newTrace, 0, causeTrace.length);
283
+                System.arraycopy(trace, 0, newTrace, causeTrace.length, trace.length);
284
+
285
+                trace = newTrace;
289 286
             }
290 287
         }
291
-        return res;
288
+
289
+        return trace;
292 290
     }
293 291
 
294 292
 }

+ 9
- 12
src/com/dmdirc/addons/scriptplugin/ScriptEngineWrapper.java View File

@@ -24,11 +24,13 @@ package com.dmdirc.addons.scriptplugin;
24 24
 
25 25
 import com.dmdirc.logger.ErrorLevel;
26 26
 import com.dmdirc.logger.Logger;
27
-import com.dmdirc.util.io.StreamUtils;
27
+
28
+import com.google.common.base.Preconditions;
28 29
 
29 30
 import java.io.File;
30 31
 import java.io.FileNotFoundException;
31 32
 import java.io.FileReader;
33
+import java.io.IOException;
32 34
 
33 35
 import javax.script.Invocable;
34 36
 import javax.script.ScriptEngine;
@@ -37,8 +39,6 @@ import javax.script.ScriptException;
37 39
 
38 40
 /**
39 41
  * Class to create script engines!
40
- *
41
- * @author Shane 'Dataforce' McCormack
42 42
  */
43 43
 public class ScriptEngineWrapper {
44 44
 
@@ -62,8 +62,9 @@ public class ScriptEngineWrapper {
62 62
      */
63 63
     protected ScriptEngineWrapper(final ScriptEngineManager scriptEngineManager,
64 64
             final String filename) throws FileNotFoundException, ScriptException {
65
+        Preconditions.checkNotNull(filename, "File cannot be null");
65 66
         this.scriptEngineManager = scriptEngineManager;
66
-        file = (filename != null) ? new File(filename) : null;
67
+        file = new File(filename);
67 68
 
68 69
         engine = createEngine();
69 70
 
@@ -107,14 +108,10 @@ public class ScriptEngineWrapper {
107 108
      */
108 109
     protected ScriptEngine createEngine() throws FileNotFoundException, ScriptException {
109 110
         final ScriptEngine result = scriptEngineManager.getEngineByName("JavaScript");
110
-        if (file != null) {
111
-            FileReader fr = null;
112
-            try {
113
-                fr = new FileReader(file);
114
-                result.eval(fr);
115
-            } finally {
116
-                StreamUtils.close(fr);
117
-            }
111
+        try (FileReader fr = new FileReader(file)) {
112
+            result.eval(fr);
113
+        } catch (IOException ex) {
114
+            throw new ScriptException(ex);
118 115
         }
119 116
 
120 117
         result.put("localHelper", localHelper);

+ 150
- 0
src/com/dmdirc/addons/scriptplugin/ScriptManager.java View File

@@ -0,0 +1,150 @@
1
+/*
2
+ * Copyright (c) 2006-2014 DMDirc Developers
3
+ *
4
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ * of this software and associated documentation files (the "Software"), to deal
6
+ * in the Software without restriction, including without limitation the rights
7
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ * copies of the Software, and to permit persons to whom the Software is
9
+ * furnished to do so, subject to the following conditions:
10
+ *
11
+ * The above copyright notice and this permission notice shall be included in
12
+ * all copies or substantial portions of the Software.
13
+ *
14
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ * SOFTWARE.
21
+ */
22
+
23
+package com.dmdirc.addons.scriptplugin;
24
+
25
+import com.dmdirc.commandline.CommandLineOptionsModule.Directory;
26
+import com.dmdirc.logger.ErrorLevel;
27
+import com.dmdirc.logger.Logger;
28
+
29
+import java.io.File;
30
+import java.io.FileNotFoundException;
31
+import java.util.Arrays;
32
+import java.util.HashMap;
33
+import java.util.LinkedList;
34
+import java.util.List;
35
+import java.util.Map;
36
+
37
+import javax.inject.Inject;
38
+import javax.script.ScriptEngineManager;
39
+import javax.script.ScriptException;
40
+
41
+public class ScriptManager {
42
+
43
+    /** Script engine manager. */
44
+    private final ScriptEngineManager scriptEngineManager;
45
+    /** Script directory. */
46
+    private final String scriptDirectory;
47
+    /** Store Script State Name,Engine */
48
+    private final Map<String, ScriptEngineWrapper> scripts = new HashMap<>();
49
+
50
+    @Inject
51
+    public ScriptManager(final ScriptEngineManager scriptEngineManager,
52
+            @Directory(ScriptModule.SCRIPTS) final String scriptDirectory) {
53
+        this.scriptEngineManager = scriptEngineManager;
54
+        this.scriptDirectory = scriptDirectory;
55
+    }
56
+
57
+    /**
58
+     * Get a clone of the scripts map.
59
+     *
60
+     * @return a clone of the scripts map
61
+     */
62
+    protected Map<String, ScriptEngineWrapper> getScripts() {
63
+        return new HashMap<>(scripts);
64
+    }
65
+
66
+    /** Reload all scripts */
67
+    public void rehash() {
68
+        for (final ScriptEngineWrapper engine : scripts.values()) {
69
+            engine.reload();
70
+        }
71
+        // Advise the Garbage collector that now would be a good time to run
72
+        System.gc();
73
+    }
74
+
75
+    /**
76
+     * Call a function in all scripts.
77
+     *
78
+     * @param functionName Name of function
79
+     * @param args         Arguments for function
80
+     */
81
+    public void callFunctionAll(final String functionName, final Object... args) {
82
+        for (final ScriptEngineWrapper engine : scripts.values()) {
83
+            engine.callFunction(functionName, args);
84
+        }
85
+    }
86
+
87
+    /**
88
+     * Load a script file into a new jsEngine
89
+     *
90
+     * @param scriptFilename Path to script
91
+     *
92
+     * @return true for Success (or already loaded), false for fail. (Fail occurs if script already
93
+     *         exists, or if it has errors)
94
+     */
95
+    public boolean loadScript(final String scriptFilename) {
96
+        if (!scripts.containsKey(scriptFilename)) {
97
+            try {
98
+                final ScriptEngineWrapper wrapper = new ScriptEngineWrapper(scriptEngineManager,
99
+                        scriptFilename);
100
+                scripts.put(scriptFilename, wrapper);
101
+            } catch (FileNotFoundException | ScriptException e) {
102
+                Logger.userError(ErrorLevel.LOW, "Error loading '" + scriptFilename + "': " + e.
103
+                        getMessage(), e);
104
+                return false;
105
+            }
106
+        }
107
+        return true;
108
+    }
109
+
110
+    /**
111
+     * Unload a script file.
112
+     *
113
+     * @param scriptFilename Path to script
114
+     */
115
+    public void unloadScript(final String scriptFilename) {
116
+        if (scripts.containsKey(scriptFilename)) {
117
+            // Tell it that its about to be unloaded.
118
+            (scripts.get(scriptFilename)).callFunction("onUnload");
119
+            // Remove the script
120
+            scripts.remove(scriptFilename);
121
+            // Advise the Garbage collector that now would be a good time to run
122
+            System.gc();
123
+        }
124
+    }
125
+
126
+    /**
127
+     * Retrieves a list of all installed scripts. Any file under the main plugin directory
128
+     * (~/.DMDirc/scripts or similar) that matches *.js is deemed to be a valid script.
129
+     *
130
+     * @return A list of all installed scripts
131
+     */
132
+    public List<String> getPossibleScripts() {
133
+        final List<String> res = new LinkedList<>();
134
+
135
+        final LinkedList<File> dirs = new LinkedList<>();
136
+        dirs.add(new File(scriptDirectory));
137
+
138
+        while (!dirs.isEmpty()) {
139
+            final File dir = dirs.pop();
140
+            if (dir.isDirectory()) {
141
+                dirs.addAll(Arrays.asList(dir.listFiles()));
142
+            } else if (dir.isFile() && dir.getName().endsWith(".js")) {
143
+                final String target = dir.getPath();
144
+                res.add(target.substring(scriptDirectory.length(), target.length()));
145
+            }
146
+        }
147
+        return res;
148
+    }
149
+
150
+}

+ 71
- 0
src/com/dmdirc/addons/scriptplugin/ScriptModule.java View File

@@ -0,0 +1,71 @@
1
+/*
2
+ * Copyright (c) 2006-2014 DMDirc Developers
3
+ *
4
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ * of this software and associated documentation files (the "Software"), to deal
6
+ * in the Software without restriction, including without limitation the rights
7
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ * copies of the Software, and to permit persons to whom the Software is
9
+ * furnished to do so, subject to the following conditions:
10
+ *
11
+ * The above copyright notice and this permission notice shall be included in
12
+ * all copies or substantial portions of the Software.
13
+ *
14
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ * SOFTWARE.
21
+ */
22
+
23
+package com.dmdirc.addons.scriptplugin;
24
+
25
+import com.dmdirc.ClientModule;
26
+import com.dmdirc.commandline.CommandLineOptionsModule.Directory;
27
+import com.dmdirc.commandline.CommandLineOptionsModule.DirectoryType;
28
+import com.dmdirc.plugins.PluginDomain;
29
+import com.dmdirc.plugins.PluginInfo;
30
+
31
+import javax.inject.Singleton;
32
+import javax.script.ScriptEngineManager;
33
+
34
+import dagger.Module;
35
+import dagger.Provides;
36
+
37
+@Module(injects = {ScriptCommand.class, ScriptManager.class, ScriptPluginManager.class},
38
+        addsTo = ClientModule.class)
39
+public class ScriptModule {
40
+
41
+    public static final String SCRIPTS = "scripts";
42
+    private final PluginInfo pluginInfo;
43
+
44
+    public ScriptModule(final PluginInfo pluginInfo) {
45
+        this.pluginInfo = pluginInfo;
46
+    }
47
+
48
+    @Provides
49
+    @PluginDomain(ScriptPlugin.class)
50
+    public String getScriptSettingsDomain() {
51
+        return pluginInfo.getDomain();
52
+    }
53
+
54
+    @Provides
55
+    @Directory(SCRIPTS)
56
+    public String getScriptsDirectory(@Directory(DirectoryType.BASE) final String baseDirectory) {
57
+        return baseDirectory + "scripts/";
58
+    }
59
+
60
+    @Provides
61
+    @Singleton
62
+    public ScriptEngineManager getScriptEngineManager() {
63
+        final JavaScriptHelper jsHelper = new JavaScriptHelper();
64
+        final TypedProperties globalVariables = new TypedProperties();
65
+        final ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
66
+        scriptEngineManager.put("globalHelper", jsHelper);
67
+        scriptEngineManager.put("globalVariables", globalVariables);
68
+        return scriptEngineManager;
69
+    }
70
+
71
+}

+ 17
- 191
src/com/dmdirc/addons/scriptplugin/ScriptPlugin.java View File

@@ -22,223 +22,49 @@
22 22
 
23 23
 package com.dmdirc.addons.scriptplugin;
24 24
 
25
-import com.dmdirc.actions.CoreActionType;
26
-import com.dmdirc.interfaces.ActionController;
27
-import com.dmdirc.interfaces.ActionListener;
28
-import com.dmdirc.interfaces.CommandController;
29
-import com.dmdirc.interfaces.actions.ActionType;
30
-import com.dmdirc.interfaces.config.IdentityController;
31
-import com.dmdirc.logger.ErrorLevel;
32
-import com.dmdirc.logger.Logger;
33 25
 import com.dmdirc.plugins.PluginInfo;
34 26
 import com.dmdirc.plugins.implementations.BaseCommandPlugin;
35 27
 import com.dmdirc.util.validators.ValidationResponse;
36 28
 
37
-import java.io.File;
38
-import java.io.FileInputStream;
39
-import java.io.FileNotFoundException;
40
-import java.io.FileOutputStream;
41
-import java.io.IOException;
42
-import java.util.HashMap;
43
-import java.util.List;
44
-import java.util.Map;
45
-
46 29
 import javax.script.ScriptEngineManager;
47
-import javax.script.ScriptException;
30
+
31
+import dagger.ObjectGraph;
48 32
 
49 33
 /**
50 34
  * This allows javascript scripts to be used in DMDirc.
51 35
  */
52
-public class ScriptPlugin extends BaseCommandPlugin implements ActionListener {
36
+public class ScriptPlugin extends BaseCommandPlugin {
53 37
 
54
-    /** Script Directory */
55
-    private final String scriptDir;
56
-    /** Script Engine Manager */
57
-    private final ScriptEngineManager ScriptEngineManager = new ScriptEngineManager();
58
-    /** Instance of the javaScriptHelper class */
59
-    private final JavaScriptHelper jsHelper = new JavaScriptHelper();
60
-    /** Store Script State Name,Engine */
61
-    private final Map<String, ScriptEngineWrapper> scripts = new HashMap<>();
62
-    /** Used to store permanent variables */
63
-    private final TypedProperties globalVariables = new TypedProperties();
64
-    /** The action controller to use. */
65
-    private final ActionController actionController;
38
+    private ScriptEngineManager scriptEngineManager;
39
+    private ScriptPluginManager scriptPluginManager;
66 40
 
67
-    /**
68
-     * Creates a new instance of the Script Plugin.
69
-     *
70
-     * @param actionController   The action controller to register listeners with
71
-     * @param identityController The Identity Manager that controls the current config
72
-     * @param commandController  Command controller to register commands
73
-     * @param pluginInfo         Plugin info object
74
-     */
75
-    public ScriptPlugin(final ActionController actionController,
76
-            final IdentityController identityController,
77
-            final CommandController commandController,
78
-            final PluginInfo pluginInfo) {
79
-        super(commandController);
80
-        scriptDir = identityController.getConfigurationDirectory() + "scripts/";
81
-        this.actionController = actionController;
41
+    @Override
42
+    public void load(final PluginInfo pluginInfo, final ObjectGraph graph) {
43
+        super.load(pluginInfo, graph);
82 44
 
83
-        // Add the JS Helper to the scriptFactory
84
-        ScriptEngineManager.put("globalHelper", jsHelper);
85
-        ScriptEngineManager.put("globalVariables", globalVariables);
86
-        registerCommand(new ScriptCommand(this, identityController, commandController, pluginInfo,
87
-                ScriptEngineManager, scriptDir), ScriptCommand.INFO);
45
+        setObjectGraph(graph.plus(new ScriptModule(pluginInfo)));
46
+        registerCommand(ScriptCommand.class, ScriptCommand.INFO);
47
+
48
+        scriptEngineManager = getObjectGraph().get(ScriptEngineManager.class);
49
+        scriptPluginManager = getObjectGraph().get(ScriptPluginManager.class);
88 50
     }
89 51
 
90 52
     /** {@inheritDoc} */
91 53
     @Override
92 54
     public void onLoad() {
93
-        // Register the plugin_loaded action initially, this will be called
94
-        // after this method finishes for us to register the rest.
95
-        actionController.registerListener(this, CoreActionType.PLUGIN_LOADED);
96
-
97
-        // Make sure our scripts dir exists
98
-        final File newDir = new File(scriptDir);
99
-        if (!newDir.exists()) {
100
-            newDir.mkdirs();
101
-        }
102
-
103
-        final File savedVariables = new File(scriptDir + "storedVariables");
104
-        if (savedVariables.exists()) {
105
-            try (FileInputStream fis = new FileInputStream(savedVariables)) {
106
-                globalVariables.load(fis);
107
-            } catch (IOException e) {
108
-                Logger.userError(ErrorLevel.LOW, "Error reading savedVariables from '"
109
-                        + savedVariables.getPath() + "': " + e.getMessage(), e);
110
-            }
111
-        }
55
+        scriptPluginManager.onLoad();
112 56
         super.onLoad();
113 57
     }
114 58
 
115 59
     @Override
116 60
     public void onUnload() {
117
-        actionController.unregisterListener(this);
118
-
119
-        final File savedVariables = new File(scriptDir + "storedVariables");
120
-        try (FileOutputStream fos = new FileOutputStream(savedVariables)) {
121
-            globalVariables.store(fos, "# DMDirc Script Plugin savedVariables");
122
-        } catch (IOException e) {
123
-            Logger.userError(ErrorLevel.LOW, "Error reading savedVariables to '" + savedVariables.
124
-                    getPath() + "': " + e.getMessage(), e);
125
-        }
61
+        scriptPluginManager.onUnLoad();
126 62
         super.onUnload();
127 63
     }
128 64
 
129
-    /**
130
-     * Register all the action types. This will unregister all the actions first.
131
-     */
132
-    private void registerAll() {
133
-        actionController.unregisterListener(this);
134
-        for (Map.Entry<String, List<ActionType>> entry
135
-                : actionController.getGroupedTypes().entrySet()) {
136
-            final List<ActionType> types = entry.getValue();
137
-            actionController.registerListener(this, types.toArray(new ActionType[types.size()]));
138
-        }
139
-    }
140
-
141
-    @Override
142
-    public void processEvent(final ActionType type, final StringBuffer format,
143
-            final Object... arguments) {
144
-        // Plugins may to register/unregister action types, so lets reregister all
145
-        // the action types. This
146
-        if (type.equals(CoreActionType.PLUGIN_LOADED) || type.equals(CoreActionType.PLUGIN_UNLOADED)) {
147
-            registerAll();
148
-        }
149
-        callFunctionAll("action_" + type.toString().toLowerCase(), arguments);
150
-    }
151
-
152
-    /**
153
-     * Get a clone of the scripts map.
154
-     *
155
-     * @return a clone of the scripts map
156
-     */
157
-    protected Map<String, ScriptEngineWrapper> getScripts() {
158
-        return new HashMap<>(scripts);
159
-    }
160
-
161
-    /**
162
-     * Get a reference to the JavaScriptHelper
163
-     *
164
-     * @return a reference to the JavaScriptHelper
165
-     */
166
-    protected JavaScriptHelper getJavaScriptHelper() {
167
-        return jsHelper;
168
-    }
169
-
170
-    /**
171
-     * Get a reference to the GlobalVariables Properties
172
-     *
173
-     * @return a reference to the GlobalVariables Properties
174
-     */
175
-    protected TypedProperties getGlobalVariables() {
176
-        return globalVariables;
177
-    }
178
-
179
-    /** Reload all scripts */
180
-    public void rehash() {
181
-        for (final ScriptEngineWrapper engine : scripts.values()) {
182
-            engine.reload();
183
-        }
184
-        // Advise the Garbage collector that now would be a good time to run
185
-        System.gc();
186
-    }
187
-
188
-    /**
189
-     * Call a function in all scripts.
190
-     *
191
-     * @param functionName Name of function
192
-     * @param args         Arguments for function
193
-     */
194
-    private void callFunctionAll(final String functionName, final Object... args) {
195
-        for (final ScriptEngineWrapper engine : scripts.values()) {
196
-            engine.callFunction(functionName, args);
197
-        }
198
-    }
199
-
200
-    /**
201
-     * Unload a script file.
202
-     *
203
-     * @param scriptFilename Path to script
204
-     */
205
-    public void unloadScript(final String scriptFilename) {
206
-        if (scripts.containsKey(scriptFilename)) {
207
-            // Tell it that its about to be unloaded.
208
-            (scripts.get(scriptFilename)).callFunction("onUnload");
209
-            // Remove the script
210
-            scripts.remove(scriptFilename);
211
-            // Advise the Garbage collector that now would be a good time to run
212
-            System.gc();
213
-        }
214
-    }
215
-
216
-    /**
217
-     * Load a script file into a new jsEngine
218
-     *
219
-     * @param scriptFilename Path to script
220
-     *
221
-     * @return true for Success (or already loaded), false for fail. (Fail occurs if script already
222
-     *         exists, or if it has errors)
223
-     */
224
-    public boolean loadScript(final String scriptFilename) {
225
-        if (!scripts.containsKey(scriptFilename)) {
226
-            try {
227
-                final ScriptEngineWrapper wrapper = new ScriptEngineWrapper(ScriptEngineManager,
228
-                        scriptFilename);
229
-                scripts.put(scriptFilename, wrapper);
230
-            } catch (FileNotFoundException | ScriptException e) {
231
-                Logger.userError(ErrorLevel.LOW, "Error loading '" + scriptFilename + "': " + e.
232
-                        getMessage(), e);
233
-                return false;
234
-            }
235
-        }
236
-        return true;
237
-    }
238
-
239 65
     @Override
240 66
     public ValidationResponse checkPrerequisites() {
241
-        if (ScriptEngineManager.getEngineByName("JavaScript") == null) {
67
+        if (scriptEngineManager.getEngineByName("JavaScript") == null) {
242 68
             return new ValidationResponse("JavaScript Scripting Engine not found.");
243 69
         } else {
244 70
             return new ValidationResponse();
@@ -251,7 +77,7 @@ public class ScriptPlugin extends BaseCommandPlugin implements ActionListener {
251 77
      * @return Human-Readable reason for checkPrerequisites failing.
252 78
      */
253 79
     public String checkPrerequisitesReason() {
254
-        if (ScriptEngineManager.getEngineByName("JavaScript") == null) {
80
+        if (scriptEngineManager.getEngineByName("JavaScript") == null) {
255 81
             return "JavaScript Scripting Engine not found.";
256 82
         } else {
257 83
             return "";

+ 118
- 0
src/com/dmdirc/addons/scriptplugin/ScriptPluginManager.java View File

@@ -0,0 +1,118 @@
1
+/*
2
+ * Copyright (c) 2006-2014 DMDirc Developers
3
+ *
4
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ * of this software and associated documentation files (the "Software"), to deal
6
+ * in the Software without restriction, including without limitation the rights
7
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ * copies of the Software, and to permit persons to whom the Software is
9
+ * furnished to do so, subject to the following conditions:
10
+ *
11
+ * The above copyright notice and this permission notice shall be included in
12
+ * all copies or substantial portions of the Software.
13
+ *
14
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ * SOFTWARE.
21
+ */
22
+
23
+package com.dmdirc.addons.scriptplugin;
24
+
25
+import com.dmdirc.actions.CoreActionType;
26
+import com.dmdirc.commandline.CommandLineOptionsModule.Directory;
27
+import com.dmdirc.interfaces.ActionController;
28
+import com.dmdirc.interfaces.ActionListener;
29
+import com.dmdirc.interfaces.actions.ActionType;
30
+import com.dmdirc.logger.ErrorLevel;
31
+import com.dmdirc.logger.Logger;
32
+
33
+import java.io.File;
34
+import java.io.FileInputStream;
35
+import java.io.FileOutputStream;
36
+import java.io.IOException;
37
+import java.util.List;
38
+import java.util.Map;
39
+
40
+import javax.inject.Inject;
41
+import javax.script.ScriptEngineManager;
42
+
43
+public class ScriptPluginManager implements ActionListener {
44
+
45
+    private final ActionController actionController;
46
+    private final String scriptDir;
47
+    private final ScriptManager scriptManager;
48
+    private final TypedProperties globalVariables;
49
+
50
+    @Inject
51
+    public ScriptPluginManager(final ActionController actionController,
52
+            @Directory(ScriptModule.SCRIPTS) final String scriptDir,
53
+            final ScriptManager scriptManager,
54
+            final ScriptEngineManager scriptEngineManager) {
55
+        this.actionController = actionController;
56
+        this.scriptDir = scriptDir;
57
+        this.scriptManager = scriptManager;
58
+        globalVariables = (TypedProperties) scriptEngineManager.get("globalVariables");
59
+    }
60
+
61
+    public void onLoad() {
62
+        // Register the plugin_loaded action initially, this will be called
63
+        // after this method finishes for us to register the rest.
64
+        actionController.registerListener(this, CoreActionType.PLUGIN_LOADED);
65
+
66
+        // Make sure our scripts dir exists
67
+        final File newDir = new File(scriptDir);
68
+        if (!newDir.exists()) {
69
+            newDir.mkdirs();
70
+        }
71
+
72
+        final File savedVariables = new File(scriptDir + "storedVariables");
73
+        if (savedVariables.exists()) {
74
+            try (FileInputStream fis = new FileInputStream(savedVariables)) {
75
+                globalVariables.load(fis);
76
+            } catch (IOException e) {
77
+                Logger.userError(ErrorLevel.LOW, "Error reading savedVariables from '"
78
+                        + savedVariables.getPath() + "': " + e.getMessage(), e);
79
+            }
80
+        }
81
+    }
82
+
83
+    public void onUnLoad() {
84
+        actionController.unregisterListener(this);
85
+
86
+        final File savedVariables = new File(scriptDir + "storedVariables");
87
+        try (FileOutputStream fos = new FileOutputStream(savedVariables)) {
88
+            globalVariables.store(fos, "# DMDirc Script Plugin savedVariables");
89
+        } catch (IOException e) {
90
+            Logger.userError(ErrorLevel.LOW, "Error reading savedVariables to '" + savedVariables.
91
+                    getPath() + "': " + e.getMessage(), e);
92
+        }
93
+    }
94
+
95
+    /**
96
+     * Register all the action types. This will unregister all the actions first.
97
+     */
98
+    private void registerAll() {
99
+        actionController.unregisterListener(this);
100
+        for (Map.Entry<String, List<ActionType>> entry
101
+                : actionController.getGroupedTypes().entrySet()) {
102
+            final List<ActionType> types = entry.getValue();
103
+            actionController.registerListener(this, types.toArray(new ActionType[types.size()]));
104
+        }
105
+    }
106
+
107
+    @Override
108
+    public void processEvent(final ActionType type, final StringBuffer format,
109
+            final Object... arguments) {
110
+        // Plugins may to register/unregister action types, so lets reregister all
111
+        // the action types, except Plugin loaded and plugin unloaded.
112
+        if (type.equals(CoreActionType.PLUGIN_LOADED) || type.equals(CoreActionType.PLUGIN_UNLOADED)) {
113
+            registerAll();
114
+        }
115
+        scriptManager.callFunctionAll("action_" + type.toString().toLowerCase(), arguments);
116
+    }
117
+
118
+}

+ 8
- 50
src/com/dmdirc/addons/scriptplugin/TypedProperties.java View File

@@ -24,23 +24,16 @@ package com.dmdirc.addons.scriptplugin;
24 24
 
25 25
 import java.io.IOException;
26 26
 import java.io.InputStream;
27
-import java.io.Reader;
28 27
 import java.util.ArrayList;
29 28
 import java.util.List;
30 29
 import java.util.Properties;
31 30
 
32 31
 /**
33
- * Properties file that allows for getting/setting of typed properties
34
- *
35
- * @author Shane 'Dataforce' McCormack
32
+ * Properties file that allows for getting/setting of typed properties.
36 33
  */
37 34
 public class TypedProperties extends Properties {
38 35
 
39
-    /**
40
-     * A version number for this class. It should be changed whenever the class structure is changed
41
-     * (or anything else that would prevent serialized objects being unserialized with the new
42
-     * class).
43
-     */
36
+    /** A version number for this class. */
44 37
     private static final long serialVersionUID = 200711071;
45 38
     /** Is this properties file Case Sensitive */
46 39
     private boolean caseSensitive = true;
@@ -73,8 +66,7 @@ public class TypedProperties extends Properties {
73 66
                 if (property instanceof String) {
74 67
                     final String propertyName = (String) property;
75 68
                     if (!propertyName.equals(propertyName.toLowerCase())) {
76
-                        super.setProperty(propertyName.toLowerCase(),
77
-                                getProperty(propertyName));
69
+                        super.setProperty(propertyName.toLowerCase(), getProperty(propertyName));
78 70
                         super.remove(propertyName);
79 71
                     }
80 72
                 }
@@ -85,7 +77,7 @@ public class TypedProperties extends Properties {
85 77
 
86 78
     /**
87 79
      * Load properties from an InputStream. After loading, setCaseSensitivity(caseSensitive) is
88
-     * called. If this properties file is ment to be case Insensitive, all non-lowercase property
80
+     * called. If this properties file is meant to be case Insensitive, all non-lowercase property
89 81
      * names will be lowercased.
90 82
      *
91 83
      * @param inStream InputStream to load from.
@@ -98,36 +90,6 @@ public class TypedProperties extends Properties {
98 90
         setCaseSensitivity(caseSensitive);
99 91
     }
100 92
 
101
-    /**
102
-     * Load properties from a Reader. After loading, setCaseSensitivity(caseSensitive) is called. If
103
-     * this properties file is ment to be case Insensitive, all non-lowercase property names will be
104
-     * lowercased.
105
-     *
106
-     * @param reader Reader to load from.
107
-     *
108
-     * @throws IOException If there is an error reading from the reader
109
-     */
110
-    @Override
111
-    public synchronized void load(final Reader reader) throws IOException {
112
-        super.load(reader);
113
-        setCaseSensitivity(caseSensitive);
114
-    }
115
-
116
-    /**
117
-     * Load properties from an XML InputStream. After loading, setCaseSensitivity(caseSensitive) is
118
-     * called. If this properties file is ment to be case Insensitive, all non-lowercase property
119
-     * names will be lowercased.
120
-     *
121
-     * @param in InputStream to load from.
122
-     *
123
-     * @throws java.io.IOException if an error occurs loading the XML
124
-     */
125
-    @Override
126
-    public synchronized void loadFromXML(final InputStream in) throws IOException {
127
-        super.loadFromXML(in);
128
-        setCaseSensitivity(caseSensitive);
129
-    }
130
-
131 93
     /**
132 94
      * Get a property from the config
133 95
      *
@@ -251,8 +213,7 @@ public class TypedProperties extends Properties {
251 213
      */
252 214
     public int getIntProperty(final String key, final int fallback) {
253 215
         try {
254
-            return Integer
255
-                    .parseInt(getProperty(key, Integer.toString(fallback)));
216
+            return Integer.parseInt(getProperty(key, Integer.toString(fallback)));
256 217
         } catch (final NumberFormatException nfe) {
257 218
             return fallback;
258 219
         }
@@ -330,8 +291,7 @@ public class TypedProperties extends Properties {
330 291
      */
331 292
     public double getDoubleProperty(final String key, final double fallback) {
332 293
         try {
333
-            return Double.parseDouble(getProperty(key, Double
334
-                    .toString(fallback)));
294
+            return Double.parseDouble(getProperty(key, Double.toString(fallback)));
335 295
         } catch (final NumberFormatException nfe) {
336 296
             return fallback;
337 297
         }
@@ -356,8 +316,7 @@ public class TypedProperties extends Properties {
356 316
      * @return the requested property, or the fallback value if not defined
357 317
      */
358 318
     public boolean getBoolProperty(final String key, final boolean fallback) {
359
-        return Boolean
360
-                .parseBoolean(getProperty(key, Boolean.toString(fallback)));
319
+        return Boolean.parseBoolean(getProperty(key, Boolean.toString(fallback)));
361 320
     }
362 321
 
363 322
     /**
@@ -405,8 +364,7 @@ public class TypedProperties extends Properties {
405 364
      *
406 365
      * @return the requested property, or the fallback value if not defined
407 366
      */
408
-    public List<String> getListProperty(final String key,
409
-            final List<String> fallback) {
367
+    public List<String> getListProperty(final String key, final List<String> fallback) {
410 368
         final String res = getProperty(key, "");
411 369
         if (res == null || res.isEmpty()) {
412 370
             return fallback;

Loading…
Cancel
Save