Created
October 13, 2012 23:58
-
-
Save aadnk/3886658 to your computer and use it in GitHub Desktop.
Simple proxy-classes for adding better error handling in Minecraft.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Logged-classes - Simple proxy-classes for adding better error handling in Minecraft. | |
* Copyright (C) 2012 Kristian S. Stangeland | |
* | |
* This library is free software; you can redistribute it and/or | |
* modify it under the terms of the GNU Library General Public | |
* License as published by the Free Software Foundation; either | |
* version 2 of the License, or (at your option) any later version. | |
* This library is distributed in the hope that it will be useful, | |
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
* Library General Public License for more details. | |
* You should have received a copy of the GNU Library General Public | |
* License along with this library; if not, write to the | |
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, | |
* Boston, MA 02110-1301, USA. | |
*/ | |
package com.comphenix.example; | |
import java.io.File; | |
import java.lang.reflect.Method; | |
import java.util.Collection; | |
import java.util.Iterator; | |
import java.util.Set; | |
import java.util.Map.Entry; | |
import org.bukkit.event.Event; | |
import org.bukkit.event.EventException; | |
import org.bukkit.event.EventPriority; | |
import org.bukkit.event.HandlerList; | |
import org.bukkit.event.Listener; | |
import org.bukkit.permissions.Permissible; | |
import org.bukkit.permissions.Permission; | |
import org.bukkit.plugin.AuthorNagException; | |
import org.bukkit.plugin.EventExecutor; | |
import org.bukkit.plugin.IllegalPluginAccessException; | |
import org.bukkit.plugin.InvalidDescriptionException; | |
import org.bukkit.plugin.InvalidPluginException; | |
import org.bukkit.plugin.Plugin; | |
import org.bukkit.plugin.PluginLoader; | |
import org.bukkit.plugin.PluginManager; | |
import org.bukkit.plugin.RegisteredListener; | |
import org.bukkit.plugin.UnknownDependencyException; | |
import com.google.common.collect.Lists; | |
public abstract class LoggedPluginManager implements PluginManager { | |
private PluginManager delegate; | |
public LoggedPluginManager(Plugin owner) { | |
this(owner.getServer().getPluginManager()); | |
} | |
public LoggedPluginManager(PluginManager delegate) { | |
this.delegate = delegate; | |
} | |
/** | |
* Invoked when an error occurs in a event listener. | |
* @param event - the event where the error occured. | |
* @param e - error that occured. | |
*/ | |
protected abstract void customHandler(Event event, Throwable e); | |
/** | |
* Registers all the events in the given listener class. | |
* @param listener - listener to register | |
* @param plugin - plugin to register | |
*/ | |
public void registerEvents(Listener listener, Plugin plugin) { | |
if (!plugin.isEnabled()) | |
throw new IllegalPluginAccessException("Plugin attempted to register " + listener + " while not enabled"); | |
// Just in case Bukkit decides to validate the parameters in the future | |
EventExecutor nullExecutor = new EventExecutor() { | |
@Override | |
public void execute(Listener arg0, Event arg1) throws EventException { | |
throw new IllegalStateException("This method should never be called!"); | |
} | |
}; | |
for (Entry<Class<? extends Event>, Set<RegisteredListener>> entry : plugin | |
.getPluginLoader().createRegisteredListeners(listener, plugin) | |
.entrySet()) { | |
Collection<RegisteredListener> listeners = entry.getValue(); | |
Collection<RegisteredListener> modified = Lists.newArrayList(); | |
// Use our plugin specific logger instead | |
for (Iterator<RegisteredListener> it = listeners.iterator(); it.hasNext(); ) { | |
final RegisteredListener delegate = it.next(); | |
RegisteredListener customListener = new RegisteredListener( | |
delegate.getListener(), nullExecutor, delegate.getPriority(), | |
delegate.getPlugin(), delegate.isIgnoringCancelled()) { | |
@Override | |
public void callEvent(Event event) throws EventException { | |
try { | |
delegate.callEvent(event); | |
} catch (AuthorNagException e) { | |
// Let Bukkit handle that one | |
throw e; | |
} catch (Throwable e) { | |
customHandler(event, e); | |
} | |
} | |
}; | |
modified.add(customListener); | |
} | |
getEventListeners(getRegistrationClass(entry.getKey())).registerAll(modified); | |
} | |
} | |
private EventExecutor getWrappedExecutor(final EventExecutor executor) { | |
return new EventExecutor() { | |
@Override | |
public void execute(Listener listener, Event event) throws EventException { | |
// Just like above | |
try { | |
executor.execute(listener, event); | |
} catch (AuthorNagException e) { | |
throw e; | |
} catch (Throwable e) { | |
customHandler(event, e); | |
} | |
} | |
}; | |
} | |
private HandlerList getEventListeners(Class<? extends Event> type) { | |
try { | |
Method method = getRegistrationClass(type).getDeclaredMethod("getHandlerList", new Class[0]); | |
method.setAccessible(true); | |
return (HandlerList) method.invoke(null, new Object[0]); | |
} catch (Exception e) { | |
throw new IllegalPluginAccessException(e.toString()); | |
} | |
} | |
private Class<? extends Event> getRegistrationClass(Class<? extends Event> clazz) { | |
try { | |
clazz.getDeclaredMethod("getHandlerList", new Class[0]); | |
return clazz; | |
} catch (NoSuchMethodException e) { | |
if ((clazz.getSuperclass() != null) | |
&& (!clazz.getSuperclass().equals(Event.class)) | |
&& (Event.class.isAssignableFrom(clazz.getSuperclass()))) { | |
return getRegistrationClass(clazz.getSuperclass().asSubclass( | |
Event.class)); | |
} | |
} | |
throw new IllegalPluginAccessException("Unable to find handler list for event " + clazz.getName()); | |
} | |
@Override | |
public void registerEvent( | |
Class<? extends Event> event, Listener listener, EventPriority priority, | |
EventExecutor executor, Plugin plugin) { | |
delegate.registerEvent(event, listener, priority, getWrappedExecutor(executor), plugin); | |
} | |
@Override | |
public void registerEvent( | |
Class<? extends Event> event, Listener listener, | |
EventPriority priority, EventExecutor executor, Plugin plugin, boolean ignoreCancel) { | |
delegate.registerEvent(event, listener, priority, getWrappedExecutor(executor), plugin); | |
} | |
@Override | |
public void registerInterface(Class<? extends PluginLoader> loader) throws IllegalArgumentException { | |
delegate.registerInterface(loader); | |
} | |
@Override | |
public void addPermission(Permission perm) { | |
delegate.addPermission(perm); | |
} | |
@Override | |
public void callEvent(Event event) throws IllegalStateException { | |
delegate.callEvent(event); | |
} | |
@Override | |
public void clearPlugins() { | |
delegate.clearPlugins(); | |
} | |
@Override | |
public void disablePlugin(Plugin plugin) { | |
delegate.disablePlugin(plugin); | |
} | |
@Override | |
public void disablePlugins() { | |
delegate.disablePlugins(); | |
} | |
@Override | |
public void enablePlugin(Plugin plugin) { | |
delegate.enablePlugin(plugin); | |
} | |
@Override | |
public Set<Permissible> getDefaultPermSubscriptions(boolean op) { | |
return delegate.getDefaultPermSubscriptions(op); | |
} | |
@Override | |
public Set<Permission> getDefaultPermissions(boolean op) { | |
return delegate.getDefaultPermissions(op); | |
} | |
@Override | |
public Permission getPermission(String name) { | |
return delegate.getPermission(name); | |
} | |
@Override | |
public Set<Permissible> getPermissionSubscriptions(String permission) { | |
return delegate.getPermissionSubscriptions(permission); | |
} | |
@Override | |
public Set<Permission> getPermissions() { | |
return delegate.getPermissions(); | |
} | |
@Override | |
public Plugin getPlugin(String name) { | |
return delegate.getPlugin(name); | |
} | |
@Override | |
public Plugin[] getPlugins() { | |
return delegate.getPlugins(); | |
} | |
@Override | |
public boolean isPluginEnabled(String name) { | |
return delegate.isPluginEnabled(name); | |
} | |
@Override | |
public boolean isPluginEnabled(Plugin plugin) { | |
return delegate.isPluginEnabled(plugin); | |
} | |
@Override | |
public Plugin loadPlugin(File file) throws InvalidPluginException, InvalidDescriptionException, UnknownDependencyException { | |
return delegate.loadPlugin(file); | |
} | |
@Override | |
public Plugin[] loadPlugins(File directory) { | |
return delegate.loadPlugins(directory); | |
} | |
@Override | |
public void recalculatePermissionDefaults(Permission permission) { | |
delegate.recalculatePermissionDefaults(permission); | |
} | |
@Override | |
public void removePermission(Permission perm) { | |
delegate.removePermission(perm); | |
} | |
@Override | |
public void removePermission(String name) { | |
delegate.removePermission(name); | |
} | |
@Override | |
public void subscribeToDefaultPerms(boolean op, Permissible permissable) { | |
delegate.subscribeToDefaultPerms(op, permissable); | |
} | |
@Override | |
public void subscribeToPermission(String permission, Permissible permissable) { | |
delegate.subscribeToPermission(permission, permissable); | |
} | |
@Override | |
public void unsubscribeFromDefaultPerms(boolean op, Permissible permissable) { | |
delegate.unsubscribeFromDefaultPerms(op, permissable); | |
} | |
@Override | |
public void unsubscribeFromPermission(String permission, Permissible permissable) { | |
delegate.unsubscribeFromPermission(permission, permissable); | |
} | |
@Override | |
public boolean useTimings() { | |
return delegate.useTimings(); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Logged-classes - Simple proxy-classes for adding better error handling in Minecraft. | |
* Copyright (C) 2012 Kristian S. Stangeland | |
* | |
* This library is free software; you can redistribute it and/or | |
* modify it under the terms of the GNU Library General Public | |
* License as published by the Free Software Foundation; either | |
* version 2 of the License, or (at your option) any later version. | |
* This library is distributed in the hope that it will be useful, | |
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
* Library General Public License for more details. | |
* You should have received a copy of the GNU Library General Public | |
* License along with this library; if not, write to the | |
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, | |
* Boston, MA 02110-1301, USA. | |
*/ | |
package com.comphenix.example; | |
import java.util.List; | |
import java.util.concurrent.Callable; | |
import java.util.concurrent.Future; | |
import org.bukkit.plugin.Plugin; | |
import org.bukkit.scheduler.BukkitScheduler; | |
import org.bukkit.scheduler.BukkitTask; | |
import org.bukkit.scheduler.BukkitWorker; | |
/** | |
* Implements a delegating scheduler that automatically handles all exceptions. | |
* @author Kristian | |
*/ | |
public abstract class LoggedScheduler implements BukkitScheduler { | |
private class TaskedRunnable implements Runnable { | |
private int taskID = -1; | |
private Runnable delegate; | |
public TaskedRunnable(Runnable delegate) { | |
this.delegate = delegate; | |
} | |
@Override | |
public void run() { | |
try { | |
delegate.run(); | |
} catch (Throwable e) { | |
customHandler(taskID, e); | |
} | |
} | |
public int getTaskID() { | |
return taskID; | |
} | |
public void setTaskID(int taskID) { | |
this.taskID = taskID; | |
} | |
} | |
// A reference to the underlying scheduler | |
private BukkitScheduler delegate; | |
public LoggedScheduler(Plugin owner) { | |
this(owner.getServer().getScheduler()); | |
} | |
public LoggedScheduler(BukkitScheduler delegate) { | |
this.delegate = delegate; | |
} | |
/** | |
* Invoked when an error occurs in a task. | |
* @param taskID - unique ID of the task, or | |
* @param e - error that occured. | |
*/ | |
protected abstract void customHandler(int taskID, Throwable e); | |
@Override | |
public <T> Future<T> callSyncMethod(Plugin plugin, Callable<T> task) { | |
return delegate.callSyncMethod(plugin, task); | |
} | |
@Override | |
public void cancelAllTasks() { | |
delegate.cancelAllTasks(); | |
} | |
@Override | |
public void cancelTask(int taskId) { | |
delegate.cancelTask(taskId); | |
} | |
@Override | |
public void cancelTasks(Plugin plugin) { | |
delegate.cancelTasks(plugin); | |
} | |
@Override | |
public List<BukkitWorker> getActiveWorkers() { | |
return delegate.getActiveWorkers(); | |
} | |
@Override | |
public List<BukkitTask> getPendingTasks() { | |
return delegate.getPendingTasks(); | |
} | |
@Override | |
public boolean isCurrentlyRunning(int taskId) { | |
return delegate.isCurrentlyRunning(taskId); | |
} | |
@Override | |
public boolean isQueued(int taskId) { | |
return delegate.isQueued(taskId); | |
} | |
@Override | |
public int scheduleAsyncDelayedTask(Plugin plugin, Runnable task) { | |
TaskedRunnable wrapped = new TaskedRunnable(task); | |
wrapped.setTaskID(delegate.scheduleAsyncDelayedTask(plugin, wrapped)); | |
return wrapped.getTaskID(); | |
} | |
@Override | |
public int scheduleAsyncDelayedTask(Plugin plugin, Runnable task, long delay) { | |
TaskedRunnable wrapped = new TaskedRunnable(task); | |
wrapped.setTaskID(delegate.scheduleAsyncDelayedTask(plugin, wrapped, delay)); | |
return wrapped.getTaskID(); | |
} | |
@Override | |
public int scheduleAsyncRepeatingTask(Plugin plugin, Runnable task, long delay, long period) { | |
TaskedRunnable wrapped = new TaskedRunnable(task); | |
wrapped.setTaskID(delegate.scheduleAsyncRepeatingTask(plugin, wrapped, delay, period)); | |
return wrapped.getTaskID(); | |
} | |
@Override | |
public int scheduleSyncDelayedTask(Plugin plugin, Runnable task) { | |
TaskedRunnable wrapped = new TaskedRunnable(task); | |
wrapped.setTaskID(delegate.scheduleSyncDelayedTask(plugin, wrapped)); | |
return wrapped.getTaskID(); | |
} | |
@Override | |
public int scheduleSyncDelayedTask(Plugin plugin, Runnable task, long delay) { | |
TaskedRunnable wrapped = new TaskedRunnable(task); | |
wrapped.setTaskID(delegate.scheduleSyncDelayedTask(plugin, wrapped, delay)); | |
return wrapped.getTaskID(); | |
} | |
@Override | |
public int scheduleSyncRepeatingTask(Plugin plugin, Runnable task, long delay, long period) { | |
TaskedRunnable wrapped = new TaskedRunnable(task); | |
wrapped.setTaskID(delegate.scheduleSyncRepeatingTask(plugin, wrapped, delay, period)); | |
return wrapped.getTaskID(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment