1 package org.bukkit.plugin.java;
4 import java.io.FileNotFoundException;
5 import java.io.IOException;
6 import java.io.InputStream;
7 import java.lang.reflect.Constructor;
8 import java.lang.reflect.InvocationTargetException;
9 import java.lang.reflect.Method;
11 import java.util.Arrays;
12 import java.util.HashMap;
13 import java.util.HashSet;
14 import java.util.LinkedHashMap;
15 import java.util.List;
18 import java.util.jar.JarEntry;
19 import java.util.jar.JarFile;
20 import java.util.logging.Level;
21 import java.util.regex.Pattern;
23 import org.apache.commons.lang.Validate;
24 import org.bukkit.Server;
25 import org.bukkit.Warning;
26 import org.bukkit.Warning.WarningState;
27 import org.bukkit.configuration.serialization.ConfigurationSerializable;
28 import org.bukkit.configuration.serialization.ConfigurationSerialization;
29 import org.bukkit.event.Event;
30 import org.bukkit.event.EventException;
31 import org.bukkit.event.EventHandler;
32 import org.bukkit.event.Listener;
33 import org.bukkit.event.server.PluginDisableEvent;
34 import org.bukkit.event.server.PluginEnableEvent;
35 import org.bukkit.plugin.AuthorNagException;
36 import org.bukkit.plugin.EventExecutor;
37 import org.bukkit.plugin.InvalidDescriptionException;
38 import org.bukkit.plugin.InvalidPluginException;
39 import org.bukkit.plugin.Plugin;
40 import org.bukkit.plugin.PluginDescriptionFile;
41 import org.bukkit.plugin.PluginLoader;
42 import org.bukkit.plugin.RegisteredListener;
43 import org.bukkit.plugin.TimedRegisteredListener;
44 import org.bukkit.plugin.UnknownDependencyException;
45 import org.yaml.snakeyaml.error.YAMLException;
47 import com.google.common.collect.ImmutableList;
57 private final Pattern[] fileFilters0 =
new Pattern[] { Pattern.compile(
"\\.jar$"), };
64 private final Map<String, Class<?>> classes0 =
new HashMap<String, Class<?>>();
69 protected final Map<String, Class<?>>
classes = classes0;
71 private final Map<String, PluginClassLoader> loaders0 =
new LinkedHashMap<String, PluginClassLoader>();
76 protected final Map<String, PluginClassLoader>
loaders = loaders0;
83 Validate.notNull(instance,
"Server cannot be null");
86 if (extended && warn) {
88 instance.
getLogger().log(Level.WARNING,
"JavaPluginLoader not intended to be extended by " + getClass() +
", and may be final in a future version of Bukkit");
93 Validate.notNull(file,
"File cannot be null");
106 File dataFolder =
new File(file.getParentFile(), description.
getName());
107 File oldDataFolder = extended ?
getDataFolder(file) : getDataFolder0(file);
110 if (dataFolder.equals(oldDataFolder)) {
112 }
else if (dataFolder.isDirectory() && oldDataFolder.isDirectory()) {
113 server.
getLogger().log(Level.INFO, String.format(
114 "While loading %s (%s) found old-data folder: %s next to the new one: %s",
120 }
else if (oldDataFolder.isDirectory() && !dataFolder.exists()) {
121 if (!oldDataFolder.renameTo(dataFolder)) {
122 throw new InvalidPluginException(
"Unable to rename old data folder: '" + oldDataFolder +
"' to: '" + dataFolder +
"'");
124 server.
getLogger().log(Level.INFO, String.format(
125 "While loading %s (%s) renamed data folder: '%s' to '%s'",
133 if (dataFolder.exists() && !dataFolder.isDirectory()) {
135 "Projected datafolder: '%s' for %s (%s) exists and is not a directory",
142 List<String> depend = description.
getDepend();
143 if (depend == null) {
144 depend = ImmutableList.<String>of();
147 for (String pluginName : depend) {
148 if (loaders0 == null) {
153 if (current == null) {
162 URL[] urls =
new URL[1];
164 urls[0] = file.toURI().toURL();
173 Class<?> jarClass = Class.forName(description.
getMain(),
true, loader);
174 Class<? extends JavaPlugin> plugin = jarClass.asSubclass(
JavaPlugin.class);
176 Constructor<? extends JavaPlugin> constructor = plugin.getConstructor();
178 result = constructor.newInstance();
180 result.
initialize(
this, server, description, dataFolder, file, loader);
181 }
catch (InvocationTargetException ex) {
183 }
catch (Throwable ex) {
187 loaders0.put(description.
getName(), loader);
198 server.
getLogger().log(Level.WARNING,
"Method \"public Plugin loadPlugin(File, boolean)\" is Deprecated, and may be removed in a future version of Bukkit",
new AuthorNagException(
""));
210 server.
getLogger().log(Level.WARNING,
"Method \"protected File getDataFolder(File)\" is Deprecated, and may be removed in a future version of Bukkit",
new AuthorNagException(
""));
213 return getDataFolder0(file);
216 private File getDataFolder0(File file) {
217 File dataFolder = null;
219 String filename = file.getName();
220 int index = file.getName().lastIndexOf(
".");
223 String name = filename.substring(0, index);
225 dataFolder =
new File(file.getParentFile(), name);
230 dataFolder =
new File(file.getParentFile(), filename +
"_");
237 Validate.notNull(file,
"File cannot be null");
240 InputStream stream = null;
243 jar =
new JarFile(file);
244 JarEntry entry = jar.getJarEntry(
"plugin.yml");
250 stream = jar.getInputStream(entry);
254 }
catch (IOException ex) {
256 }
catch (YAMLException ex) {
262 }
catch (IOException e) {
265 if (stream != null) {
268 }
catch (IOException e) {
275 return fileFilters0.clone();
284 server.
getLogger().log(Level.WARNING,
"Method \"public Class<?> getClassByName(String)\" is Deprecated, and may be removed in a future version of Bukkit",
new AuthorNagException(
""));
287 return getClassByName0(name);
290 Class<?> getClassByName0(
final String name) {
291 Class<?> cachedClass = classes0.get(name);
293 if (cachedClass != null) {
296 for (String current : loaders0.keySet()) {
297 PluginClassLoader loader = loaders0.get(current);
300 cachedClass = loader.extended ? loader.findClass(name,
false) : loader.findClass0(name,
false);
301 }
catch (ClassNotFoundException cnfe) {}
302 if (cachedClass != null) {
314 public void setClass(
final String name,
final Class<?> clazz) {
316 server.
getLogger().log(Level.WARNING,
"Method \"public void setClass(String, Class<?>)\" is Deprecated, and may be removed in a future version of Bukkit",
new AuthorNagException(
""));
319 setClass0(name, clazz);
322 void setClass0(
final String name,
final Class<?> clazz) {
323 if (!classes0.containsKey(name)) {
324 classes0.put(name, clazz);
339 server.
getLogger().log(Level.WARNING,
"Method \"public void removeClass(String)\" is Deprecated, and may be removed in a future version of Bukkit",
new AuthorNagException(
""));
345 private void removeClass0(String name) {
346 Class<?> clazz = classes0.remove(name);
353 }
catch (NullPointerException ex) {
360 Validate.notNull(plugin,
"Plugin can not be null");
361 Validate.notNull(listener,
"Listener can not be null");
364 Map<Class<? extends Event>, Set<RegisteredListener>> ret =
new HashMap<Class<? extends Event>, Set<RegisteredListener>>();
367 Method[] publicMethods = listener.getClass().getMethods();
368 methods =
new HashSet<Method>(publicMethods.length, Float.MAX_VALUE);
369 for (Method method : publicMethods) {
372 for (Method method : listener.getClass().getDeclaredMethods()) {
375 }
catch (NoClassDefFoundError e) {
376 plugin.
getLogger().severe(
"Plugin " + plugin.
getDescription().
getFullName() +
" has failed to register events for " + listener.getClass() +
" because " + e.getMessage() +
" does not exist.");
380 for (
final Method method : methods) {
382 if (eh == null)
continue;
383 final Class<?> checkClass = method.getParameterTypes()[0];
384 if (!
Event.class.isAssignableFrom(checkClass) || method.getParameterTypes().length != 1) {
385 plugin.
getLogger().severe(plugin.
getDescription().
getFullName() +
" attempted to register an invalid EventHandler method signature \"" + method.toGenericString() +
"\" in " + listener.getClass());
388 final Class<? extends Event> eventClass = checkClass.asSubclass(
Event.class);
389 method.setAccessible(
true);
390 Set<RegisteredListener> eventSet = ret.get(eventClass);
391 if (eventSet == null) {
392 eventSet =
new HashSet<RegisteredListener>();
393 ret.put(eventClass, eventSet);
396 for (Class<?> clazz = eventClass;
Event.class.isAssignableFrom(clazz); clazz = clazz.getSuperclass()) {
398 if (clazz.getAnnotation(Deprecated.class) != null) {
401 if (!warningState.
printFor(warning)) {
407 "\"%s\" has registered a listener for %s on method \"%s\", but the event is Deprecated." +
408 " \"%s\"; please notify the authors %s.",
411 method.toGenericString(),
412 (warning != null && warning.
reason().length() != 0) ? warning.
reason() :
"Server performance will be affected",
422 if (!eventClass.isAssignableFrom(event.getClass())) {
425 method.invoke(listener, event);
426 }
catch (InvocationTargetException ex) {
428 }
catch (Throwable t) {
443 Validate.isTrue(plugin instanceof
JavaPlugin,
"Plugin is not associated with this PluginLoader");
448 JavaPlugin jPlugin = (JavaPlugin) plugin;
452 if (!loaders0.containsKey(pluginName)) {
458 }
catch (Throwable ex) {
469 Validate.isTrue(plugin instanceof
JavaPlugin,
"Plugin is not associated with this PluginLoader");
477 JavaPlugin jPlugin = (JavaPlugin) plugin;
482 }
catch (Throwable ex) {
489 PluginClassLoader loader = (PluginClassLoader) cloader;
490 Set<String> names = loader.extended ? loader.
getClasses() : loader.getClasses0();
492 for (String name : names) {