/** * Loads the plugins contained within the specified directory * * @param directory Directory to check for plugins * @return A list of all plugins loaded */ public Plugin[] loadPlugins(File directory) { Validate.notNull(directory, "Directory cannot be null"); Validate.isTrue(directory.isDirectory(), "Directory must be a directory"); List<Plugin> result = new ArrayList<Plugin>(); Set<Pattern> filters = fileAssociations.keySet(); if (!(server.getUpdateFolder().equals(""))) { updateDirectory = new File(directory, server.getUpdateFolder()); } Map<String, File> plugins = new HashMap<String, File>(); Set<String> loadedPlugins = new HashSet<String>(); Map<String, Collection<String>> dependencies = new HashMap<String, Collection<String>>(); Map<String, Collection<String>> softDependencies = new HashMap<String, Collection<String>>(); // This is where it figures out all possible plugins for (File file : directory.listFiles()) { PluginLoader loader = null; for (Pattern filter : filters) { Matcher match = filter.matcher(file.getName()); if (match.find()) { loader = fileAssociations.get(filter); } } if (loader == null) continue; PluginDescriptionFile description = null; try { description = loader.getPluginDescription(file); } catch (InvalidDescriptionException ex) { server .getLogger() .log( Level.SEVERE, "Could not load '" + file.getPath() + "' in folder '" + directory.getPath() + "'", ex); continue; } plugins.put(description.getName(), file); Collection<String> softDependencySet = description.getSoftDepend(); if (softDependencySet != null) { if (softDependencies.containsKey(description.getName())) { // Duplicates do not matter, they will be removed together if applicable softDependencies.get(description.getName()).addAll(softDependencySet); } else { softDependencies.put(description.getName(), new LinkedList<String>(softDependencySet)); } } Collection<String> dependencySet = description.getDepend(); if (dependencySet != null) { dependencies.put(description.getName(), new LinkedList<String>(dependencySet)); } Collection<String> loadBeforeSet = description.getLoadBefore(); if (loadBeforeSet != null) { for (String loadBeforeTarget : loadBeforeSet) { if (softDependencies.containsKey(loadBeforeTarget)) { softDependencies.get(loadBeforeTarget).add(description.getName()); } else { // softDependencies is never iterated, so 'ghost' plugins aren't an issue Collection<String> shortSoftDependency = new LinkedList<String>(); shortSoftDependency.add(description.getName()); softDependencies.put(loadBeforeTarget, shortSoftDependency); } } } } while (!plugins.isEmpty()) { boolean missingDependency = true; Iterator<String> pluginIterator = plugins.keySet().iterator(); while (pluginIterator.hasNext()) { String plugin = pluginIterator.next(); if (dependencies.containsKey(plugin)) { Iterator<String> dependencyIterator = dependencies.get(plugin).iterator(); while (dependencyIterator.hasNext()) { String dependency = dependencyIterator.next(); // Dependency loaded if (loadedPlugins.contains(dependency)) { dependencyIterator.remove(); // We have a dependency not found } else if (!plugins.containsKey(dependency)) { missingDependency = false; File file = plugins.get(plugin); pluginIterator.remove(); softDependencies.remove(plugin); dependencies.remove(plugin); server .getLogger() .log( Level.SEVERE, "Could not load '" + file.getPath() + "' in folder '" + directory.getPath() + "'", new UnknownDependencyException(dependency)); break; } } if (dependencies.containsKey(plugin) && dependencies.get(plugin).isEmpty()) { dependencies.remove(plugin); } } if (softDependencies.containsKey(plugin)) { Iterator<String> softDependencyIterator = softDependencies.get(plugin).iterator(); while (softDependencyIterator.hasNext()) { String softDependency = softDependencyIterator.next(); // Soft depend is no longer around if (!plugins.containsKey(softDependency)) { softDependencyIterator.remove(); } } if (softDependencies.get(plugin).isEmpty()) { softDependencies.remove(plugin); } } if (!(dependencies.containsKey(plugin) || softDependencies.containsKey(plugin)) && plugins.containsKey(plugin)) { // We're clear to load, no more soft or hard dependencies left File file = plugins.get(plugin); pluginIterator.remove(); missingDependency = false; try { result.add(loadPlugin(file)); loadedPlugins.add(plugin); continue; } catch (InvalidPluginException ex) { server .getLogger() .log( Level.SEVERE, "Could not load '" + file.getPath() + "' in folder '" + directory.getPath() + "'", ex); } } } if (missingDependency) { // We now iterate over plugins until something loads // This loop will ignore soft dependencies pluginIterator = plugins.keySet().iterator(); while (pluginIterator.hasNext()) { String plugin = pluginIterator.next(); if (!dependencies.containsKey(plugin)) { softDependencies.remove(plugin); missingDependency = false; File file = plugins.get(plugin); pluginIterator.remove(); try { result.add(loadPlugin(file)); loadedPlugins.add(plugin); break; } catch (InvalidPluginException ex) { server .getLogger() .log( Level.SEVERE, "Could not load '" + file.getPath() + "' in folder '" + directory.getPath() + "'", ex); } } } // We have no plugins left without a depend if (missingDependency) { softDependencies.clear(); dependencies.clear(); Iterator<File> failedPluginIterator = plugins.values().iterator(); while (failedPluginIterator.hasNext()) { File file = failedPluginIterator.next(); failedPluginIterator.remove(); server .getLogger() .log( Level.SEVERE, "Could not load '" + file.getPath() + "' in folder '" + directory.getPath() + "': circular dependency detected"); } } } } return result.toArray(new Plugin[result.size()]); }
@Override public String getUpdateFolder() { return server.getUpdateFolder(); }