File Source: PluginManager.java
/*
P/P * Method: com.dmdirc.plugins.PluginManager__static_init
*/
1 /*
2 * Copyright (c) 2006-2009 Chris Smith, Shane Mc Cormack, Gregory Holmes
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 package com.dmdirc.plugins;
23
24 import com.dmdirc.Main;
25 import com.dmdirc.actions.ActionManager;
26 import com.dmdirc.actions.CoreActionType;
27 import com.dmdirc.actions.interfaces.ActionType;
28 import com.dmdirc.config.IdentityManager;
29 import com.dmdirc.config.prefs.PreferencesManager;
30 import com.dmdirc.interfaces.ActionListener;
31 import com.dmdirc.logger.Logger;
32 import com.dmdirc.logger.ErrorLevel;
33 import com.dmdirc.updater.components.PluginComponent;
34
35 import java.io.File;
36 import java.net.URL;
37 import java.net.MalformedURLException;
38 import java.util.ArrayList;
39 import java.util.Collection;
40 import java.util.Hashtable;
41 import java.util.LinkedList;
42 import java.util.List;
43 import java.util.Map;
44 import java.util.HashMap;
45
46 /**
47 * Searches for and manages plugins and services.
48 *
49 * @author shane
50 * @author chris
51 */
52 public class PluginManager implements ActionListener {
53
54 /** List of known plugins' file names to their corresponding {@link PluginInfo} objects. */
55 private final Map<String, PluginInfo> knownPlugins = new Hashtable<String, PluginInfo>();
56
57 /** Directory where plugins are stored. */
58 private final String myDir;
59
60 /** Singleton instance of the plugin manager. */
61 private static PluginManager me;
62
63 /** Map of services. */
64 private final Map<String, Map<String, Service>> services = new HashMap<String, Map<String, Service>>();
65
66 /**
67 * Creates a new instance of PluginManager.
68 */
/*
P/P * Method: void com.dmdirc.plugins.PluginManager()
*
* Presumptions:
* init'ed(com.dmdirc.actions.CoreActionType.CLIENT_PREFS_CLOSED)
* init'ed(com.dmdirc.actions.CoreActionType.CLIENT_PREFS_OPENED)
*
* Postconditions:
* java.lang.StringBuilder:toString(...)._tainted == 0
* this.knownPlugins == &new Hashtable(PluginManager#1)
* this.myDir == &java.lang.StringBuilder:toString(...)
* this.services == &new HashMap(PluginManager#2)
* new HashMap(PluginManager#2) num objects == 1
* new Hashtable(PluginManager#1) num objects == 1
*/
69 private PluginManager() {
70 final String fs = System.getProperty("file.separator");
71 myDir = Main.getConfigDir() + "plugins" + fs;
72 ActionManager.addListener(this, CoreActionType.CLIENT_PREFS_OPENED, CoreActionType.CLIENT_PREFS_CLOSED);
73 }
74
75 /**
76 * Get a service object for the given name/type if one exists.
77 *
78 * @param type Type of this service
79 * @param name Name of this service
80 * @return The service requested, or null if service wasn't found and create wasn't specifed
81 */
82 public Service getService(final String type, final String name) {
/*
P/P * Method: Service getService(String, String)
*
* Preconditions:
* this.services != null
*
* Postconditions:
* init'ed(return_value)
* new ArrayList(Service#1) num objects == 0
* new Service(getService#1*) num objects == 0
* new Service(getService#3*) num objects == 0
* not_init'ed(new Service(getService#1*).name)
* not_init'ed(new Service(getService#3*).name)
* init'ed(new Service(getService#1*).serviceproviders)
* not_init'ed(new Service(getService#1*).type)
* not_init'ed(new Service(getService#3*).type)
* not_init'ed(new Service(getService#3*).serviceproviders)
*/
83 return getService(type, name, false);
84 }
85
86 /**
87 * Get a service object for the given name/type.
88 *
89 * @param type Type of this service
90 * @param name Name of this service
91 * @param create If the requested service doesn't exist, should it be created?
92 * @return The service requested, or null if service wasn't found and create wasn't specifed
93 */
94 public Service getService(final String type, final String name, final boolean create) {
95 // Find the type first
/*
P/P * Method: Service getService(String, String, bool)
*
* Preconditions:
* this.services != null
*
* Presumptions:
* java.util.Map:get(...)@97 != null
*
* Postconditions:
* init'ed(return_value)
* new ArrayList(Service#1) num objects <= 1
* new Service(getService#1) num objects <= 1
* new Service(getService#1).name == name
* init'ed(new Service(getService#1).name)
* init'ed(new Service(getService#1).serviceproviders)
* new Service(getService#1).type == type
* init'ed(new Service(getService#1).type)
* new Service(getService#3) num objects <= 1
* new Service(getService#3).name == name
* ...
*
* Test Vectors:
* create: {0}, {1}
* java.util.Map:containsKey(...)@96: {0}, {1}
* java.util.Map:containsKey(...)@99: {0}, {1}
*/
96 if (services.containsKey(type)) {
97 final Map<String, Service> map = services.get(type);
98 // Now the name
99 if (map.containsKey(name)) {
100 return map.get(name);
101 } else if (create) {
102 final Service service = new Service(type, name);
103 map.put(name, service);
104 return service;
105 }
106 } else if (create) {
107 final Map<String, Service> map = new HashMap<String, Service>();
108 final Service service = new Service(type, name);
109 map.put(name, service);
110 services.put(type, map);
111 return service;
112 }
113
114 return null;
115 }
116
117 /**
118 * Get a ServiceProvider object for the given name/type if one exists.
119 *
120 * @param type Type of this service
121 * @param name Name of this service
122 * @return A ServiceProvider that provides the requested service.
123 * @throws NoSuchProviderException If no provider exists for the requested service
124 */
125 public ServiceProvider getServiceProvider(final String type, final String name) throws NoSuchProviderException {
/*
P/P * Method: ServiceProvider getServiceProvider(String, String)
*
* Preconditions:
* this.services != null
*
* Postconditions:
* return_value != null
*/
126 final Service service = getService(type, name);
127 if (service != null) {
128 ServiceProvider provider = service.getActiveProvider();
129 if (provider != null) {
130 return provider;
131 } else {
132 // Try to activate the service then try again.
133 service.activate();
134 provider = service.getActiveProvider();
135 if (provider != null) {
136 return provider;
137 }
138 }
139 }
140
141 throw new NoSuchProviderException("No provider found for: "+type+"->"+name);
142 }
143
144 /**
145 * Get a ServiceProvider object for the given tpye, prioritising those in the list of names.
146 *
147 * @param type Type to look for
148 * @param names Names to look for
149 * @param fallback Fallback to the first provider of type that exists if one from the list is not found.
150 * @return A ServiceProvider that provides the requested service.
151 * @throws NoSuchProviderException If no provider exists for the requested service and fallback is false, or no providers exist at all.
152 */
153 public ServiceProvider getServiceProvider(final String type, final List<String> names, final boolean fallback) throws NoSuchProviderException {
/*
P/P * Method: ServiceProvider getServiceProvider(String, List, bool)
*
* Preconditions:
* names != null
* (soft) fallback == 1
* (soft) this.services != null
*
* Presumptions:
* java.util.List:get(...)@164 != null
* java.util.List:size(...)@163 >= 1
*
* Postconditions:
* return_value != null
*
* Test Vectors:
* java.util.Iterator:hasNext(...)@154: {0}, {1}
*/
154 for (final String name : names) {
155 final ServiceProvider provider = getServiceProvider(type, name);
156 if (provider != null) {
157 return provider;
158 }
159 }
160
161 if (fallback) {
162 final List<Service> servicesType = getServicesByType(type);
163 if (servicesType.size() > 0) {
164 final Service service = servicesType.get(0);
165 return getServiceProvider(type, service.getName());
166 }
167 }
168
169 throw new NoSuchProviderException("No provider found for "+type+ "from the given list");
170 }
171
172 /**
173 * Get an ExportedService object of the given name from any provider that provides it.
174 * This is the same as doing getServiceProvider("export", name).getExportedService(name)
175 *
176 * @param name Name of this service
177 * @return An ExportedService object.
178 * @throws NoSuchProviderException If no provider exists for the requested service.
179 */
180 public ExportedService getExportedService(final String name) {
/*
P/P * Method: ExportedService getExportedService(String)
*
* Preconditions:
* this.services != null
* (soft) com/dmdirc/plugins/GlobalClassLoader.me != null
*
* Presumptions:
* getServiceProvider(...).exports@181 != null
*
* Postconditions:
* init'ed(com/dmdirc/plugins/GlobalClassLoader.me)
* return_value == One-of{&new ExportedService(getExportedService#1*), &new ExportedService(getExportedService#2*)}
* return_value in Addr_Set{&new ExportedService(getExportedService#1*),&new ExportedService(getExportedService#2*),&new ExportedService(getExportedService#1*)}
* new ExportedService(getExportedService#1*) num objects <= 1
* init'ed(new ExportedService(getExportedService#1*).myMethod)
* init'ed(new ExportedService(getExportedService#1*).myObject)
* new ExportedService(getExportedService#1*).myObject == null
* new ExportedService(getExportedService#2*) num objects <= 1
* init'ed(new ExportedService(getExportedService#2*).myMethod)
* new ExportedService(getExportedService#2*).myObject == null
* ...
*/
181 return getServiceProvider("export", name).getExportedService(name);
182 }
183
184 /**
185 * Get a List of all services of a specifed type.
186 *
187 * @param type Type of service
188 * @return The list of services requested.
189 */
190 public List<Service> getServicesByType(final String type) {
191 // Find the type first
/*
P/P * Method: List getServicesByType(String)
*
* Preconditions:
* this.services != null
*
* Presumptions:
* java.util.Map:get(...)@193 != null
*
* Postconditions:
* return_value in Addr_Set{&new ArrayList(getServicesByType#2),&new ArrayList(getServicesByType#1)}
* new ArrayList(getServicesByType#1) num objects <= 1
* new ArrayList(getServicesByType#2) num objects <= 1
*
* Test Vectors:
* java.util.Map:containsKey(...)@192: {0}, {1}
*/
192 if (services.containsKey(type)) {
193 final Map<String, Service> map = services.get(type);
194 return new ArrayList<Service>(map.values());
195 }
196
197 return new ArrayList<Service>();
198 }
199
200 /**
201 * Get a List of all services
202 *
203 * @return The list of all services.
204 */
205 public List<Service> getAllServices() {
206 // Find the type first
/*
P/P * Method: List getAllServices()
*
* Preconditions:
* this.services != null
*
* Presumptions:
* java.util.Iterator:next(...)@208 != null
* java.util.Map:values(...)@208 != null
*
* Postconditions:
* return_value == &new ArrayList(getAllServices#1)
* new ArrayList(getAllServices#1) num objects == 1
*
* Test Vectors:
* java.util.Iterator:hasNext(...)@208: {0}, {1}
*/
207 final List<Service> allServices = new ArrayList<Service>();
208 for (Map<String, Service> map : services.values()) {
209 allServices.addAll(map.values());
210 }
211
212 return allServices;
213 }
214
215 /**
216 * Autoloads plugins.
217 */
218 public void doAutoLoad() {
/*
P/P * Method: void doAutoLoad()
*
* Preconditions:
* (soft) this.knownPlugins != null
*
* Presumptions:
* com.dmdirc.config.ConfigManager:getOptionList(...)@219 != null
* com.dmdirc.config.IdentityManager:getGlobalConfig(...)@219 != null
* java.util.Iterator:next(...)@219 != null
* java.util.Map:get(...)@348 != null
*
* Test Vectors:
* java.lang.String:charAt(...)@221: {35}, {0..34, 36..216-1}
* java.lang.String:isEmpty(...)@221: {1}, {0}
* java.util.Iterator:hasNext(...)@219: {0}, {1}
* java.util.Map:get(...)@348: Addr_Set{null}, Inverse{null}
*/
219 for (String plugin : IdentityManager.getGlobalConfig().getOptionList("plugins", "autoload")) {
220 plugin = plugin.trim();
221 if (!plugin.isEmpty() && plugin.charAt(0) != '#' && getPluginInfo(plugin) != null) {
222 getPluginInfo(plugin).loadPlugin();
223 }
224 }
225 }
226
227 /**
228 * Retrieves the singleton instance of the plugin manager.
229 *
230 * @return A singleton instance of PluginManager.
231 */
232 public static final synchronized PluginManager getPluginManager() {
/*
P/P * Method: PluginManager getPluginManager()
*
* Preconditions:
* init'ed(me)
*
* Postconditions:
* java.lang.StringBuilder:toString(...)._tainted == 0
* me == One-of{old me, &new PluginManager(getPluginManager#1)}
* me != null
* return_value == me
* new HashMap(PluginManager#2) num objects <= 1
* new Hashtable(PluginManager#1) num objects <= 1
* new PluginClassLoader(getSubClassLoader#1) num objects == undefined
* new PluginClassLoader(getSubClassLoader#1) num objects == 0, if init'ed
* new PluginClassLoader(getSubClassLoader#1).pluginInfo == undefined
* new PluginClassLoader(getSubClassLoader#1).pluginInfo == null
* ...
*
* Test Vectors:
* me: Inverse{null}, Addr_Set{null}
*/
233 if (me == null) {
234 me = new PluginManager();
235 me.getPossiblePluginInfos(true);
236 }
237
238
239 return me;
240 }
241
242 /**
243 * Tests and adds the specified plugin to the known plugins list. Plugins
244 * will only be added if: <ul><li>The file exists,<li>No other plugin with
245 * the same name is known,<li>All requirements are met for the plugin,
246 * <li>The plugin has a valid config file that can be read</ul>.
247 *
248 * @param filename Filename of Plugin jar
249 * @return True if the plugin is in the known plugins list (either before
250 * this invocation or as a result of it), false if it was not added for
251 * one of the reasons outlined above.
252 */
253 public boolean addPlugin(final String filename) {
/*
P/P * Method: bool addPlugin(String)
*
* Preconditions:
* filename != null
* this.knownPlugins != null
* (soft) com.dmdirc.logger.ErrorManager__static_init.new Class[](ErrorManager__static_init#2)[...] != null
* (soft) init'ed(com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).logReports)
* (soft) com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).nextErrorID != null
* (soft) init'ed(com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).sendReports)
* (soft) init'ed(com.dmdirc.ui.FatalErrorDialog$4__static_init.new int[](FatalErrorDialog$4__static_init#1)[...])
* (soft) init'ed(com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).reportThread)
* (soft) init'ed(com/dmdirc/logger/ProgramError.errorDir)
*
* Presumptions:
* java.lang.String:isEmpty(...)@273 == 1
* pluginInfo.requirementsError@270 != null
*
* Postconditions:
* com/dmdirc/logger/ProgramError.errorDir == One-of{old com/dmdirc/logger/ProgramError.errorDir, &new File(getErrorFile#1)}
* init'ed(com/dmdirc/logger/ProgramError.errorDir)
* init'ed(return_value)
* com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).reportThread == old com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).reportThread
* init'ed(com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).reportThread)
* new ErrorReportingThread(sendError#1) num objects == 0
* init'ed(new ErrorReportingThread(sendError#1).queue)
* new File(getErrorFile#1) num objects <= 1
*
* Test Vectors:
* java.io.File:exists(...)@258: {1}, {0}
* java.util.Map:containsKey(...)@254: {0}, {1}
*/
254 if (knownPlugins.containsKey(filename.toLowerCase())) {
255 return true;
256 }
257
258 if (!new File(getDirectory() + filename).exists()) {
259 Logger.userError(ErrorLevel.MEDIUM, "Error loading plugin " + filename + ": File does not exist");
260 return false;
261 }
262
263 try {
264 final PluginInfo pluginInfo = new PluginInfo(new URL("file:"+getDirectory()+filename));
265 final PluginInfo existing = getPluginInfoByName(pluginInfo.getName());
266 if (existing != null) {
267 Logger.userError(ErrorLevel.MEDIUM, "Duplicate Plugin detected, Ignoring. (" + filename + " is the same as " + existing.getFilename() + ")");
268 return false;
269 }
270 new PluginComponent(pluginInfo);
271
272 final String requirements = pluginInfo.getRequirementsError();
273 if (requirements.isEmpty()) {
274 knownPlugins.put(filename.toLowerCase(), pluginInfo);
275
276 return true;
277 } else {
278 throw new PluginException("Plugin "+filename+" was not loaded, one or more requirements not met ("+requirements+")");
279 }
280 } catch (MalformedURLException mue) {
281 Logger.userError(ErrorLevel.MEDIUM, "Error creating URL for plugin " + filename + ": " + mue.getMessage(), mue);
282 } catch (PluginException e) {
283 Logger.userError(ErrorLevel.MEDIUM, "Error loading plugin " + filename + ": " + e.getMessage(), e);
284 }
285
286 return false;
287 }
288
289 /**
290 * Remove a plugin.
291 *
292 * @param filename Filename of Plugin jar
293 * @return True if removed.
294 */
295 public boolean delPlugin(final String filename) {
/*
P/P * Method: bool delPlugin(String)
*
* Preconditions:
* filename != null
* this.knownPlugins != null
*
* Presumptions:
* java.util.Map:get(...)@348 != null
* pluginInfo.children@300 != null
* pluginInfo.plugin@300 != null
* pluginInfo.provides@300 != null
*
* Postconditions:
* init'ed(java.lang.StringBuilder:toString(...)._tainted)
* possibly_updated(java.lang.StringBuilder:toString(...)._tainted)
* init'ed(return_value)
* init'ed(new PluginClassLoader(getSubClassLoader#1) num objects)
* possibly_updated(new PluginClassLoader(getSubClassLoader#1).pluginInfo)
*
* Test Vectors:
* java.util.Map:containsKey(...)@296: {1}, {0}
*/
296 if (!knownPlugins.containsKey(filename.toLowerCase())) {
297 return false;
298 }
299
300 PluginInfo pluginInfo = getPluginInfo(filename);
301
302 pluginInfo.unloadPlugin();
303
304 knownPlugins.remove(filename.toLowerCase());
305
306 return true;
307 }
308
309 /**
310 * Reload a plugin.
311 *
312 * @param filename Filename of Plugin jar
313 * @return True if reloaded.
314 */
315 public boolean reloadPlugin(final String filename) {
/*
P/P * Method: bool reloadPlugin(String)
*
* Preconditions:
* filename != null
* this.knownPlugins != null
* (soft) init'ed(com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).reportThread)
* (soft) init'ed(com/dmdirc/logger/ProgramError.errorDir)
*
* Presumptions:
* java.util.Map:get(...)@348 != null
*
* Postconditions:
* com/dmdirc/logger/ProgramError.errorDir == old com/dmdirc/logger/ProgramError.errorDir
* init'ed(java.lang.StringBuilder:toString(...)._tainted)
* possibly_updated(java.lang.StringBuilder:toString(...)._tainted)
* init'ed(return_value)
* com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).reportThread == old com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).reportThread
* new ErrorReportingThread(sendError#1) num objects == undefined
* new ErrorReportingThread(sendError#1) num objects == 0, if init'ed
* new File(getErrorFile#1) num objects == new ErrorReportingThread(sendError#1) num objects
* new ErrorReportingThread(sendError#1).queue == undefined
* new ErrorReportingThread(sendError#1).queue == null
* ...
*
* Test Vectors:
* addPlugin(...)@322: {0}, {1}
* java.util.Map:containsKey(...)@316: {1}, {0}
*/
316 if (!knownPlugins.containsKey(filename.toLowerCase())) {
317 return false;
318 }
319
320 final boolean wasLoaded = getPluginInfo(filename).isLoaded();
321 delPlugin(filename);
322 boolean result = addPlugin(filename);
323
324 if (wasLoaded && result) {
325 getPluginInfo(filename).loadPlugin();
326 result = getPluginInfo(filename).isLoaded();
327 }
328
329 return result;
330 }
331
332 /**
333 * Reload all plugins.
334 */
335 public void reloadAllPlugins() {
/*
P/P * Method: void reloadAllPlugins()
*
* Preconditions:
* this.knownPlugins != null
*
* Presumptions:
* java.util.Iterator:next(...)@336 != null
*
* Postconditions:
* java.lang.StringBuilder:toString(...)._tainted == 0
* new PluginClassLoader(getSubClassLoader#1) num objects == undefined
* new PluginClassLoader(getSubClassLoader#1) num objects == 0, if init'ed
* new PluginClassLoader(getSubClassLoader#1).pluginInfo == undefined
* new PluginClassLoader(getSubClassLoader#1).pluginInfo == null
*
* Test Vectors:
* java.util.Iterator:hasNext(...)@336: {0}, {1}
*/
336 for (PluginInfo pluginInfo : getPluginInfos()) {
337 reloadPlugin(pluginInfo.getFilename());
338 }
339 }
340
341 /**
342 * Get a plugin instance.
343 *
344 * @param filename File name of plugin jar
345 * @return PluginInfo instance, or null
346 */
347 public PluginInfo getPluginInfo(final String filename) {
/*
P/P * Method: PluginInfo getPluginInfo(String)
*
* Preconditions:
* filename != null
* this.knownPlugins != null
*
* Postconditions:
* init'ed(return_value)
*/
348 return knownPlugins.get(filename.toLowerCase());
349 }
350
351 /**
352 * Get a plugin instance by plugin name.
353 *
354 * @param name Name of plugin to find.
355 * @return PluginInfo instance, or null
356 */
357 public PluginInfo getPluginInfoByName(final String name) {
/*
P/P * Method: PluginInfo getPluginInfoByName(String)
*
* Preconditions:
* this.knownPlugins != null
*
* Presumptions:
* java.util.Iterator:next(...)@358 != null
*
* Postconditions:
* init'ed(return_value)
*
* Test Vectors:
* java.lang.String:equalsIgnoreCase(...)@359: {0}, {1}
* java.util.Iterator:hasNext(...)@358: {0}, {1}
*/
358 for (PluginInfo pluginInfo : getPluginInfos()) {
359 if (pluginInfo.getName().equalsIgnoreCase(name)) {
360 return pluginInfo;
361 }
362 }
363
364 return null;
365 }
366
367 /**
368 * Get directory where plugins are stored.
369 *
370 * @return Directory where plugins are stored.
371 */
372 public String getDirectory() {
/*
P/P * Method: String getDirectory()
*
* Postconditions:
* return_value == this.myDir
* init'ed(return_value)
*/
373 return myDir;
374 }
375
376 /**
377 * Retrieves a list of all installed plugins.
378 * Any file under the main plugin directory (~/.DMDirc/plugins or similar)
379 * that matches *.jar is deemed to be a valid plugin.
380 *
381 * @param addPlugins Should all found plugins be automatically have addPlugin() called?
382 * @return A list of all installed plugins
383 */
384 public List<PluginInfo> getPossiblePluginInfos(final boolean addPlugins) {
/*
P/P * Method: List getPossiblePluginInfos(bool)
*
* Preconditions:
* (soft) com.dmdirc.logger.ErrorManager__static_init.new Class[](ErrorManager__static_init#2)[...] != null
* (soft) init'ed(com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).logReports)
* (soft) com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).nextErrorID != null
* (soft) init'ed(com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).sendReports)
* (soft) init'ed(com.dmdirc.ui.FatalErrorDialog$4__static_init.new int[](FatalErrorDialog$4__static_init#1)[...])
* (soft) init'ed(com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).reportThread)
* (soft) init'ed(com/dmdirc/logger/ProgramError.errorDir)
* (soft) this.knownPlugins != null
* (soft) this.myDir != null
*
* Presumptions:
* arr$.length@394 <= 232-1
* java.io.File:getName(...)@397 != null
* java.io.File:getPath(...)@398 != null
* java.io.File:listFiles(...)@394 != null
* java.util.Iterator:next(...)@416 != null
* ...
*
* Postconditions:
* init'ed(com/dmdirc/logger/ProgramError.errorDir)
* init'ed(java.lang.StringBuilder:toString(...)._tainted)
* possibly_updated(java.lang.StringBuilder:toString(...)._tainted)
* return_value == &new LinkedList(getPossiblePluginInfos#10)
* init'ed(com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).reportThread)
* init'ed(new ErrorReportingThread(sendError#1) num objects)
* new ErrorReportingThread(sendError#1) num objects == undefined
* new ErrorReportingThread(sendError#1) num objects == 0, if init'ed
* new File(getErrorFile#1) num objects == new ErrorReportingThread(sendError#1) num objects
* init'ed(new ErrorReportingThread(sendError#1).queue)
* ...
*
* Test Vectors:
* addPlugins: {0}, {1}
* java.io.File:exists(...)@417: {1}, {0}
* java.io.File:isDirectory(...)@393: {0}, {1}
* java.io.File:isFile(...)@397: {0}, {1}
* java.lang.String:endsWith(...)@397: {0}, {1}
* java.util.Iterator:hasNext(...)@416: {0}, {1}
* java.util.LinkedList:isEmpty(...)@391: {1}, {0}
*/
385 final Map<String, PluginInfo> res = new Hashtable<String, PluginInfo>();
386
387 final LinkedList<File> dirs = new LinkedList<File>();
388
389 dirs.add(new File(myDir));
390
391 while (!dirs.isEmpty()) {
392 final File dir = dirs.pop();
393 if (dir.isDirectory()) {
394 for (File file : dir.listFiles()) {
395 dirs.add(file);
396 }
397 } else if (dir.isFile() && dir.getName().endsWith(".jar")) {
398 String target = dir.getPath();
399
400 // Remove the plugin dir
401 target = target.substring(myDir.length(), target.length());
402 if (addPlugins) {
403 addPlugin(target);
404 } else {
405 try {
406 final PluginInfo pi = new PluginInfo(new URL("file:"+getDirectory()+target), false);
407 res.put(target, pi);
408 } catch (MalformedURLException mue) {
409 Logger.userError(ErrorLevel.MEDIUM, "Error creating URL for plugin " + target + ": " + mue.getMessage(), mue);
410 } catch (PluginException pe) { /* This can not be thrown when the second param is false */}
411 }
412 }
413 }
414
415 final Map<String, PluginInfo> knownPluginsCopy = new Hashtable<String, PluginInfo>(knownPlugins);
416 for (PluginInfo pi : knownPluginsCopy.values()) {
417 if (!(new File(pi.getFullFilename())).exists()) {
418 delPlugin(pi.getFilename());
419 } else if (addPlugins) {
420 res.put(pi.getFilename().toLowerCase(), pi);
421 }
422 }
423
424 return new LinkedList<PluginInfo>(res.values());
425 }
426
427 /**
428 * Update the autoLoadList
429 *
430 * @param plugin to add/remove (Decided automatically based on isLoaded())
431 */
432 public void updateAutoLoad(final PluginInfo plugin) {
/*
P/P * Method: void updateAutoLoad(PluginInfo)
*
* Preconditions:
* plugin != null
* init'ed(plugin.plugin)
* (soft) init'ed(plugin.tempLoaded)
*
* Presumptions:
* com.dmdirc.config.ConfigManager:getOptionList(...)@433 != null
* com.dmdirc.config.IdentityManager:getConfigIdentity(...)@442 != null
* com.dmdirc.config.IdentityManager:getGlobalConfig(...)@433 != null
*
* Test Vectors:
* !(plugin.plugin == null) & plugin.tempLoaded == 0: {0}, {1}
* java.util.List:contains(...)@436: {1}, {0}
* java.util.List:contains(...)@438: {0}, {1}
*/
433 final List<String> list = IdentityManager.getGlobalConfig().getOptionList("plugins", "autoload");
434 final String path = plugin.getRelativeFilename();
435
436 if (plugin.isLoaded() && !list.contains(path)) {
437 list.add(path);
438 } else if (!plugin.isLoaded() && list.contains(path)) {
439 list.remove(path);
440 }
441
442 IdentityManager.getConfigIdentity().setOption("plugins", "autoload", list);
443 }
444
445 /**
446 * Get Collection<PluginInfo> of known plugins.
447 *
448 * @return Collection<PluginInfo> of known plugins.
449 */
450 public Collection<PluginInfo> getPluginInfos() {
/*
P/P * Method: Collection getPluginInfos()
*
* Preconditions:
* this.knownPlugins != null
*
* Postconditions:
* return_value == &new ArrayList(getPluginInfos#1)
* new ArrayList(getPluginInfos#1) num objects == 1
*/
451 return new ArrayList<PluginInfo>(knownPlugins.values());
452 }
453
454 /** {@inheritDoc} */
455 @Override
456 public void processEvent(final ActionType type, final StringBuffer format, final Object... arguments) {
/*
P/P * Method: void processEvent(ActionType, StringBuffer, Object[])
*
* Preconditions:
* type != null
* (soft) arguments != null
* (soft) arguments.length >= 1
* (soft) init'ed(arguments[0])
* (soft) com.dmdirc.logger.ErrorManager__static_init.new Class[](ErrorManager__static_init#2)[...] != null
* (soft) init'ed(com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).logReports)
* (soft) com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).nextErrorID != null
* (soft) init'ed(com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).sendReports)
* (soft) init'ed(com.dmdirc.ui.FatalErrorDialog$4__static_init.new int[](FatalErrorDialog$4__static_init#1)[...])
* (soft) init'ed(com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).reportThread)
* ...
*
* Presumptions:
* init'ed(com.dmdirc.actions.CoreActionType.CLIENT_PREFS_CLOSED)
* init'ed(com.dmdirc.actions.CoreActionType.CLIENT_PREFS_OPENED)
* java.util.Iterator:next(...)@458 != null
* java.util.Iterator:next(...)@471 != null
* pi.children@471 != null
* ...
*
* Postconditions:
* init'ed(com/dmdirc/logger/ProgramError.errorDir)
* init'ed(java.lang.StringBuilder:toString(...)._tainted)
* possibly_updated(java.lang.StringBuilder:toString(...)._tainted)
* init'ed(com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).reportThread)
* init'ed(new ErrorReportingThread(sendError#1) num objects)
* init'ed(new ErrorReportingThread(sendError#1).queue)
* init'ed(new File(getErrorFile#1) num objects)
* init'ed(new PluginClassLoader(getSubClassLoader#1) num objects)
* init'ed(new PluginClassLoader(getSubClassLoader#1).pluginInfo)
*
* Test Vectors:
* java.lang.Object:equals(...)@457: {0}, {1}
* java.lang.Object:equals(...)@470: {0}, {1}
* java.util.Iterator:hasNext(...)@471: {0}, {1}
* pi.tempLoaded@458: {0}, {1}
*/
457 if (type.equals(CoreActionType.CLIENT_PREFS_OPENED)) {
458 for (PluginInfo pi : getPluginInfos()) {
459 if (!pi.isLoaded() && !pi.isTempLoaded()) {
460 pi.loadPluginTemp();
461 }
462 if (pi.isLoaded() || pi.isTempLoaded()) {
463 try {
464 pi.getPlugin().showConfig((PreferencesManager) arguments[0]);
465 } catch (Throwable t) {
466 Logger.userError(ErrorLevel.MEDIUM, "Error with plugin ("+pi.getNiceName()+"), unable to show config ("+t+")", t);
467 }
468 }
469 }
470 } else if (type.equals(CoreActionType.CLIENT_PREFS_CLOSED)) {
471 for (PluginInfo pi : getPluginInfos()) {
472 if (pi.isTempLoaded()) {
473 pi.unloadPlugin();
474 }
475 }
476 }
477 }
478 }
SofCheck Inspector Build Version : 2.17854
| PluginManager.java |
2009-Jun-25 01:54:24 |
| PluginManager.class |
2009-Sep-02 17:04:12 |