Skip to content

Commit

Permalink
Reverse roles of manager and loader in discovery.
Browse files Browse the repository at this point in the history
The PluginLoader is now itself responsible for iterating a plugin
directory, because we're keeping different loaders' plugins in
subdirectories. (The data directory of the loader's plugin.)

The JavaPluginLoader is the only exception, which still reads from
the main plugin directory.

This also neatly tucks away system plugin functionality, which is
Java-specific, in the JavaPluginLoader.
  • Loading branch information
Stéphan Kochen committed Feb 25, 2011
1 parent 4be7c9c commit bbc3182
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 93 deletions.
28 changes: 12 additions & 16 deletions src/main/java/org/bukkit/plugin/PluginLoader.java
@@ -1,8 +1,5 @@
package org.bukkit.plugin;

import java.io.File;
import java.util.regex.Pattern;

import org.bukkit.event.Event;
import org.bukkit.event.Listener;

Expand All @@ -18,11 +15,6 @@
* @see JavaPluginLoader
*/
public interface PluginLoader {
/**
* Returns a list of all filename filters expected by this PluginLoader
*/
public Pattern[] getPluginFileFilters();

/**
* Creates and returns an event executor
*
Expand All @@ -32,18 +24,22 @@ public interface PluginLoader {
public EventExecutor createExecutor(Event.Type type, Listener listener);

/**
* Reads the description for the plugin in the specified file
* Find plugins, and read their descriptions.
*
* Called by the PluginManager to find out about, or get an update on
* plugins handled by this loader.
*
* The loader should look for plugins in the data folder of it's own
* containing plugin, which can be retrieved using
* {@link PluginDescription#getDataFolder()}.
*
* The implementation gathers the necessary information, usually
* with help from metadata included with the plugin, and returns
* a PluginDescription subclass.
* For each plugin it finds, the implementation constructs an instance of
* PluginDescription, and registers it using
* {@link PluginManager#register(PluginDescription)}.
*
* @param pluginFile The file containing the plugin
* @return A filled PluginDescription object
* @throws InvalidDescriptionException Thrown when the metadata was not understood
* @see PluginDescription
*/
public PluginDescription readDescription(File pluginFile) throws InvalidDescriptionException;
public void discoverPlugins();

/**
* Called by PluginManager to enable a plugin
Expand Down
26 changes: 9 additions & 17 deletions src/main/java/org/bukkit/plugin/PluginManager.java
Expand Up @@ -19,29 +19,21 @@ public interface PluginManager {
public void registerInterface(PluginLoader loader);

/**
* Rediscover and reindex all plugins
* Registers a plugin description
*
* Walks the plugin directory, reads descriptions and rebuilds the index
* of all plugins it can find for the registered loaders.
* Typically called from {@link PluginLoader#discoverPlugins()}.
*
* @param description The description to register
*/
public void rebuildIndex();
public void register(PluginDescription description);

/**
* Discover and add to the index plugins handled by the given loader.
*
* This method is similar to {@link #rebuildIndex()}, but iterates only
* the plugins that match the given loader's filename filters, and adds
* those to the index, (rather than clearing the index and rebuilding
* from scratch.)
*
* This method is useful for plugins defining new interfaces. Those
* should call this method to index newly available plugins, and then
* call {@link #enablePlugin(PluginDescription)} for each returned.
* Rediscover and reindex all plugins
*
* @param loader The loader of the type of plugin to index.
* @return A list of plugin descriptions that was indexed.
* Walks the plugin directory, reads descriptions and rebuilds the index
* of all plugins it can find for the registered loaders.
*/
public PluginDescription[] updateIndexForInterface(PluginLoader loader);
public void rebuildIndex();

/**
* Checks if the given plugin is loaded and returns it when applicable
Expand Down
59 changes: 11 additions & 48 deletions src/main/java/org/bukkit/plugin/SimplePluginManager.java
Expand Up @@ -13,9 +13,7 @@
import java.util.TreeSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import org.bukkit.Server;
import java.util.regex.Pattern;

import org.bukkit.command.CommandMap;
import org.bukkit.command.SimpleCommandMap;
Expand All @@ -33,7 +31,6 @@
public final class SimplePluginManager implements PluginManager {
private final Server server;
private final File pluginFolder;
private final List<File> systemPlugins;
private final CommandMap commandMap;
private final List<PluginLoader> pluginLoaders = new ArrayList<PluginLoader>();
private final JavaPluginLoader javaPluginLoader;
Expand Down Expand Up @@ -64,10 +61,13 @@ public int compare(RegisteredListener i, RegisteredListener j) {
public SimplePluginManager(Server server, File pluginFolder, List<File> systemPlugins) {
this.server = server;
this.pluginFolder = pluginFolder;
this.systemPlugins = systemPlugins;
this.commandMap = new SimpleCommandMap(server);

javaPluginLoader = new JavaPluginLoader(server);
if (!pluginFolder.exists()) {
pluginFolder.mkdir();
}

javaPluginLoader = new JavaPluginLoader(server, pluginFolder, systemPlugins);
registerInterface(javaPluginLoader);
}

Expand All @@ -81,56 +81,19 @@ public void registerInterface(PluginLoader loader) {
/**
* {@inheritDoc}
*/
public void rebuildIndex() {
pluginDescriptions.clear();

for (PluginLoader loader : pluginLoaders) {
updateIndexForInterface(loader);
}

for (File file : systemPlugins) {
try {
PluginDescription description = javaPluginLoader.readSystemPluginDescription(file);
if (pluginDescriptions.contains(description)) {
throw new InvalidDescriptionException("A plugin with this name already exists: " + description.getName());
}
pluginDescriptions.insert(description);
} catch (InvalidDescriptionException ex) {
server.getLogger().log(Level.SEVERE, "Could not load " + file.getPath() + " in " + pluginFolder.getPath() + ": " + ex.getMessage(), ex);
}
}
public void register(PluginDescription description) {
pluginDescriptions.insert(description);
}

/**
* {@inheritDoc}
*/
public PluginDescription[] updateIndexForInterface(PluginLoader loader) {
if (!pluginFolder.exists()) {
pluginFolder.mkdir();
}
public void rebuildIndex() {
pluginDescriptions.clear();

File[] files = pluginFolder.listFiles();
Pattern[] filters = loader.getPluginFileFilters();
ArrayList<PluginDescription> result = new ArrayList<PluginDescription>();
for (Pattern filter : filters) {
for (File file : files) {
Matcher match = filter.matcher(file.getName());
if (match.find()) {
try {
PluginDescription description = loader.readDescription(file);
if (pluginDescriptions.contains(description)) {
throw new InvalidDescriptionException("A plugin with this name already exists: " + description.getName());
}
pluginDescriptions.insert(description);
result.add(description);
} catch (InvalidDescriptionException ex) {
server.getLogger().log(Level.SEVERE, "Could not load " + file.getPath() + " in " + pluginFolder.getPath() + ": " + ex.getMessage(), ex);
}
}
}
for (PluginLoader loader : pluginLoaders) {
loader.discoverPlugins();
}

return result.toArray(new PluginDescription[0]);
}

/**
Expand Down
54 changes: 42 additions & 12 deletions src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java
Expand Up @@ -12,7 +12,9 @@
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.regex.Pattern;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.bukkit.Server;
import org.bukkit.command.Command;
import org.bukkit.command.CommandMap;
Expand All @@ -34,19 +36,16 @@
* Represents a Java plugin loader, allowing plugins in the form of .jar
*/
public final class JavaPluginLoader implements PluginLoader {
private static final Logger log = Logger.getLogger(JavaPluginLoader.class.getName());
private final Server server;
private final Pattern[] fileFilters = new Pattern[] { Pattern.compile("\\.jar$"), };
private final File pluginFolder;
private final List<File> systemPlugins;
private final Map<String, Class<?>> classes = new HashMap<String, Class<?>>();

public JavaPluginLoader(Server instance) {
server = instance;
}

/**
* {@inheritDoc}
*/
public Pattern[] getPluginFileFilters() {
return fileFilters;
public JavaPluginLoader(Server server, File pluginFolder, List<File> systemPlugins) {
this.server = server;
this.pluginFolder = pluginFolder;
this.systemPlugins = systemPlugins;
}

/**
Expand Down Expand Up @@ -372,7 +371,38 @@ public void execute( Listener listener, Event event ) {
/**
* {@inheritDoc}
*/
public PluginDescription readDescription(File file) throws InvalidDescriptionException {
public void discoverPlugins() {
PluginManager manager = server.getPluginManager();
for (File file : pluginFolder.listFiles()) {
if (!file.getName().endsWith(".jar")) {
continue;
}
try {
PluginDescription description = readDescription(file);
manager.register(description);
} catch (InvalidDescriptionException ex) {
log.log(Level.SEVERE, "Could not load " + file.getPath() + " in " + pluginFolder.getPath() + ": " + ex.getMessage(), ex);
}
}

for (File file : systemPlugins) {
try {
PluginDescription description = readSystemPluginDescription(file);
manager.register(description);
} catch (InvalidDescriptionException ex) {
log.log(Level.SEVERE, "Could not load " + file.getPath() + " in " + pluginFolder.getPath() + ": " + ex.getMessage(), ex);
}
}
}

/**
* Reads the description for the plugin in the specified JAR-file
*
* @param file The JAR-file containing the plugin
* @return A PluginDescription instance
* @throws InvalidDescriptionException Thrown when the metadata was not understood
*/
private PluginDescription readDescription(File file) throws InvalidDescriptionException {
JavaPluginDescription result = null;

if (!file.exists()) {
Expand Down

0 comments on commit bbc3182

Please sign in to comment.