diff --git a/api/pom.xml b/api/pom.xml
index 0eee082c..b5834e96 100644
--- a/api/pom.xml
+++ b/api/pom.xml
@@ -31,6 +31,12 @@
1.7.14compile
+
+ net.md-5
+ bungeecord-event
+ ${project.version}
+ compile
+ org.yamlsnakeyaml
diff --git a/api/src/main/java/com/google/common/eventbus/AnnotatedHandlerFinder.java b/api/src/main/java/com/google/common/eventbus/AnnotatedHandlerFinder.java
deleted file mode 100644
index 8ea01451..00000000
--- a/api/src/main/java/com/google/common/eventbus/AnnotatedHandlerFinder.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2007 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.eventbus;
-
-import com.google.common.base.Throwables;
-import com.google.common.cache.CacheBuilder;
-import com.google.common.cache.CacheLoader;
-import com.google.common.cache.LoadingCache;
-import com.google.common.collect.HashMultimap;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Multimap;
-import com.google.common.reflect.TypeToken;
-import com.google.common.util.concurrent.UncheckedExecutionException;
-
-import java.lang.reflect.Method;
-import java.util.Set;
-
-/**
- * A {@link HandlerFindingStrategy} for collecting all event handler methods that are marked with
- * the {@link Subscribe} annotation.
- *
- * @author Cliff Biffle
- * @author Louis Wasserman
- */
-class AnnotatedHandlerFinder implements HandlerFindingStrategy {
- /**
- * A thread-safe cache that contains the mapping from each class to all methods in that class and
- * all super-classes, that are annotated with {@code @Subscribe}. The cache is shared across all
- * instances of this class; this greatly improves performance if multiple EventBus instances are
- * created and objects of the same class are registered on all of them.
- */
- private static final LoadingCache, ImmutableList> handlerMethodsCache =
- CacheBuilder.newBuilder()
- .weakKeys()
- .build(new CacheLoader, ImmutableList>() {
- @Override
- public ImmutableList load(Class> concreteClass) throws Exception {
- return getAnnotatedMethodsInternal(concreteClass);
- }
- });
-
- /**
- * {@inheritDoc}
- *
- * This implementation finds all methods marked with a {@link Subscribe} annotation.
- */
- @Override
- public Multimap, EventHandler> findAllHandlers(Object listener) {
- Multimap, EventHandler> methodsInListener = HashMultimap.create();
- Class> clazz = listener.getClass();
- for (Method method : getAnnotatedMethods(clazz)) {
- Class>[] parameterTypes = method.getParameterTypes();
- Class> eventType = parameterTypes[0];
- EventHandler handler = new EventHandler(listener, method);
- methodsInListener.put(eventType, handler);
- }
- return methodsInListener;
- }
-
- private static ImmutableList getAnnotatedMethods(Class> clazz) {
- try {
- return handlerMethodsCache.getUnchecked(clazz);
- } catch (UncheckedExecutionException e) {
- throw Throwables.propagate(e.getCause());
- }
- }
-
- private static ImmutableList getAnnotatedMethodsInternal(Class> clazz) {
- Set extends Class>> supers = TypeToken.of(clazz).getTypes().rawTypes();
- ImmutableList.Builder result = ImmutableList.builder();
- for (Method method : clazz.getMethods()) {
- /*
- * Iterate over each distinct method of {@code clazz}, checking if it is annotated with
- * @Subscribe by any of the superclasses or superinterfaces that declare it.
- */
- for (Class> c : supers) {
- try {
- Method m = c.getMethod(method.getName(), method.getParameterTypes());
- if (m.isAnnotationPresent(Subscribe.class)) {
- Class>[] parameterTypes = method.getParameterTypes();
- if (parameterTypes.length != 1) {
- throw new IllegalArgumentException("Method " + method
- + " has @Subscribe annotation, but requires " + parameterTypes.length
- + " arguments. Event handler methods must require a single argument.");
- }
- Class> eventType = parameterTypes[0];
- result.add(method);
- break;
- }
- } catch (NoSuchMethodException ignored) {
- // Move on.
- }
- }
- }
- return result.build();
- }
-}
diff --git a/api/src/main/java/com/google/common/eventbus/EventBus.java b/api/src/main/java/com/google/common/eventbus/EventBus.java
deleted file mode 100644
index 9360a155..00000000
--- a/api/src/main/java/com/google/common/eventbus/EventBus.java
+++ /dev/null
@@ -1,330 +0,0 @@
-/*
- * Copyright (C) 2007 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.eventbus;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import com.google.common.annotations.Beta;
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Throwables;
-import com.google.common.cache.CacheBuilder;
-import com.google.common.cache.CacheLoader;
-import com.google.common.cache.LoadingCache;
-import com.google.common.collect.HashMultimap;
-import com.google.common.collect.Multimap;
-import com.google.common.collect.SetMultimap;
-import com.google.common.reflect.TypeToken;
-import com.google.common.util.concurrent.UncheckedExecutionException;
-
-import java.lang.reflect.InvocationTargetException;
-import java.util.Collection;
-import java.util.LinkedList;
-import java.util.Map.Entry;
-import java.util.Queue;
-import java.util.Set;
-import java.util.concurrent.locks.ReadWriteLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-/**
- * Dispatches events to listeners, and provides ways for listeners to register
- * themselves.
- *
- *
The EventBus allows publish-subscribe-style communication between
- * components without requiring the components to explicitly register with one
- * another (and thus be aware of each other). It is designed exclusively to
- * replace traditional Java in-process event distribution using explicit
- * registration. It is not a general-purpose publish-subscribe system,
- * nor is it intended for interprocess communication.
- *
- *
Receiving Events
- * To receive events, an object should:
- *
Expose a public method, known as the event handler, which accepts
- * a single argument of the type of event desired;
- *
Mark it with a {@link Subscribe} annotation;
- *
Pass itself to an EventBus instance's {@link #register(Object)} method.
- *
- *
- *
- *
Posting Events
- * To post an event, simply provide the event object to the
- * {@link #post(Object)} method. The EventBus instance will determine the type
- * of event and route it to all registered listeners.
- *
- *
Events are routed based on their type — an event will be delivered
- * to any handler for any type to which the event is assignable. This
- * includes implemented interfaces, all superclasses, and all interfaces
- * implemented by superclasses.
- *
- *
When {@code post} is called, all registered handlers for an event are run
- * in sequence, so handlers should be reasonably quick. If an event may trigger
- * an extended process (such as a database load), spawn a thread or queue it for
- * later. (For a convenient way to do this, use an {@link AsyncEventBus}.)
- *
- *
Handler Methods
- * Event handler methods must accept only one argument: the event.
- *
- *
Handlers should not, in general, throw. If they do, the EventBus will
- * catch and log the exception. This is rarely the right solution for error
- * handling and should not be relied upon; it is intended solely to help find
- * problems during development.
- *
- *
The EventBus guarantees that it will not call a handler method from
- * multiple threads simultaneously, unless the method explicitly allows it by
- * bearing the {@link AllowConcurrentEvents} annotation. If this annotation is
- * not present, handler methods need not worry about being reentrant, unless
- * also called from outside the EventBus.
- *
- *
Dead Events
- * If an event is posted, but no registered handlers can accept it, it is
- * considered "dead." To give the system a second chance to handle dead events,
- * they are wrapped in an instance of {@link DeadEvent} and reposted.
- *
- *
If a handler for a supertype of all events (such as Object) is registered,
- * no event will ever be considered dead, and no DeadEvents will be generated.
- * Accordingly, while DeadEvent extends {@link Object}, a handler registered to
- * receive any Object will never receive a DeadEvent.
- *
- *
This class is safe for concurrent use.
- *
- *
See the Guava User Guide article on
- * {@code EventBus}.
- *
- * @author Cliff Biffle
- * @since 10.0
- */
-@Beta
-public class EventBus {
-
- /**
- * A thread-safe cache for flattenHierarchy(). The Class class is immutable. This cache is shared
- * across all EventBus instances, which greatly improves performance if multiple such instances
- * are created and objects of the same class are posted on all of them.
- */
- private static final LoadingCache, Set>> flattenHierarchyCache =
- CacheBuilder.newBuilder()
- .weakKeys()
- .build(new CacheLoader, Set>>() {
- @SuppressWarnings({"unchecked", "rawtypes"}) // safe cast
- @Override
- public Set> load(Class> concreteClass) {
- return (Set) TypeToken.of(concreteClass).getTypes().rawTypes();
- }
- });
-
- /**
- * All registered event handlers, indexed by event type.
- *
- *
This SetMultimap is NOT safe for concurrent use; all access should be
- * made after acquiring a read or write lock via {@link #handlersByTypeLock}.
- */
- private final SetMultimap, EventHandler> handlersByType =
- HashMultimap.create();
- private final ReadWriteLock handlersByTypeLock = new ReentrantReadWriteLock();
-
- /**
- * Logger for event dispatch failures. Named by the fully-qualified name of
- * this class, followed by the identifier provided at construction.
- */
- private final Logger logger;
-
- /**
- * Strategy for finding handler methods in registered objects. Currently,
- * only the {@link AnnotatedHandlerFinder} is supported, but this is
- * encapsulated for future expansion.
- */
- private final HandlerFindingStrategy finder = new AnnotatedHandlerFinder();
-
- /** queues of events for the current thread to dispatch */
- private final ThreadLocal> eventsToDispatch =
- new ThreadLocal>() {
- @Override protected Queue initialValue() {
- return new LinkedList();
- }
- };
-
- /**
- * Creates a new EventBus named "default".
- */
- public EventBus() {
- this("default");
- }
-
- /**
- * Creates a new EventBus with the given {@code identifier}.
- *
- * @param identifier a brief name for this bus, for logging purposes. Should
- * be a valid Java identifier.
- */
- public EventBus(String identifier) {
- logger = Logger.getLogger(EventBus.class.getName() + "." + checkNotNull(identifier));
- }
-
- /**
- * Registers all handler methods on {@code object} to receive events.
- * Handler methods are selected and classified using this EventBus's
- * {@link HandlerFindingStrategy}; the default strategy is the
- * {@link AnnotatedHandlerFinder}.
- *
- * @param object object whose handler methods should be registered.
- */
- public void register(Object object) {
- Multimap, EventHandler> methodsInListener =
- finder.findAllHandlers(object);
- handlersByTypeLock.writeLock().lock();
- try {
- handlersByType.putAll(methodsInListener);
- } finally {
- handlersByTypeLock.writeLock().unlock();
- }
- }
-
- /**
- * Unregisters all handler methods on a registered {@code object}.
- *
- * @param object object whose handler methods should be unregistered.
- * @throws IllegalArgumentException if the object was not previously registered.
- */
- public void unregister(Object object) {
- Multimap, EventHandler> methodsInListener = finder.findAllHandlers(object);
- for (Entry, Collection> entry : methodsInListener.asMap().entrySet()) {
- Class> eventType = entry.getKey();
- Collection eventMethodsInListener = entry.getValue();
-
- handlersByTypeLock.writeLock().lock();
- try {
- Set currentHandlers = handlersByType.get(eventType);
- if (!currentHandlers.containsAll(eventMethodsInListener)) {
- throw new IllegalArgumentException(
- "missing event handler for an annotated method. Is " + object + " registered?");
- }
- currentHandlers.removeAll(eventMethodsInListener);
- } finally {
- handlersByTypeLock.writeLock().unlock();
- }
- }
- }
-
- /**
- * Posts an event to all registered handlers. This method will return
- * successfully after the event has been posted to all handlers, and
- * regardless of any exceptions thrown by handlers.
- *
- *
If no handlers have been subscribed for {@code event}'s class, and
- * {@code event} is not already a {@link DeadEvent}, it will be wrapped in a
- * DeadEvent and reposted.
- *
- * @param event event to post.
- */
- public void post(Object event) {
- Set> dispatchTypes = flattenHierarchy(event.getClass());
-
- boolean dispatched = false;
- for (Class> eventType : dispatchTypes) {
- handlersByTypeLock.readLock().lock();
- try {
- Set wrappers = handlersByType.get(eventType);
-
- if (!wrappers.isEmpty()) {
- dispatched = true;
- for (EventHandler wrapper : wrappers) {
- enqueueEvent(event, wrapper);
- }
- }
- } finally {
- handlersByTypeLock.readLock().unlock();
- }
- }
-
- if (!dispatched && !(event instanceof DeadEvent)) {
- post(new DeadEvent(this, event));
- }
-
- dispatchQueuedEvents();
- }
-
- /**
- * Queue the {@code event} for dispatch during
- * {@link #dispatchQueuedEvents()}. Events are queued in-order of occurrence
- * so they can be dispatched in the same order.
- */
- void enqueueEvent(Object event, EventHandler handler) {
- eventsToDispatch.get().offer(new EventWithHandler(event, handler));
- }
-
- /**
- * Drain the queue of events to be dispatched. As the queue is being drained,
- * new events may be posted to the end of the queue.
- */
- void dispatchQueuedEvents() {
- try {
- Queue events = eventsToDispatch.get();
- EventWithHandler eventWithHandler;
- while ((eventWithHandler = events.poll()) != null) {
- dispatch(eventWithHandler.event, eventWithHandler.handler);
- }
- } finally {
- eventsToDispatch.remove();
- }
- }
-
- /**
- * Dispatches {@code event} to the handler in {@code wrapper}. This method
- * is an appropriate override point for subclasses that wish to make
- * event delivery asynchronous.
- *
- * @param event event to dispatch.
- * @param wrapper wrapper that will call the handler.
- */
- void dispatch(Object event, EventHandler wrapper) {
- try {
- wrapper.handleEvent(event);
- } catch (InvocationTargetException e) {
- logger.log(Level.SEVERE,
- "Could not dispatch event: " + event + " to handler " + wrapper, e);
- }
- }
-
- /**
- * Flattens a class's type hierarchy into a set of Class objects. The set
- * will include all superclasses (transitively), and all interfaces
- * implemented by these superclasses.
- *
- * @param concreteClass class whose type hierarchy will be retrieved.
- * @return {@code clazz}'s complete type hierarchy, flattened and uniqued.
- */
- @VisibleForTesting
- Set> flattenHierarchy(Class> concreteClass) {
- try {
- return flattenHierarchyCache.getUnchecked(concreteClass);
- } catch (UncheckedExecutionException e) {
- throw Throwables.propagate(e.getCause());
- }
- }
-
- /** simple struct representing an event and it's handler */
- static class EventWithHandler {
- final Object event;
- final EventHandler handler;
- public EventWithHandler(Object event, EventHandler handler) {
- this.event = checkNotNull(event);
- this.handler = checkNotNull(handler);
- }
- }
-}
diff --git a/api/src/main/java/net/md_5/bungee/api/plugin/PluginManager.java b/api/src/main/java/net/md_5/bungee/api/plugin/PluginManager.java
index de5a1b81..06d282e6 100644
--- a/api/src/main/java/net/md_5/bungee/api/plugin/PluginManager.java
+++ b/api/src/main/java/net/md_5/bungee/api/plugin/PluginManager.java
@@ -1,10 +1,10 @@
package net.md_5.bungee.api.plugin;
import com.google.common.base.Preconditions;
-import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import java.io.File;
import java.io.InputStream;
+import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;
@@ -20,7 +20,8 @@ import lombok.RequiredArgsConstructor;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.ProxyServer;
-import net.md_5.bungee.api.event.LoginEvent;
+import net.md_5.bungee.event.EventBus;
+import net.md_5.bungee.event.EventHandler;
import org.yaml.snakeyaml.Yaml;
/**
@@ -36,7 +37,8 @@ public class PluginManager
private final ProxyServer proxy;
/*========================================================================*/
private final Yaml yaml = new Yaml();
- private final EventBus eventBus = new EventBus();
+ @SuppressWarnings("unchecked")
+ private final EventBus eventBus = new EventBus( ProxyServer.getInstance().getLogger(), Subscribe.class, EventHandler.class );
private final Map plugins = new HashMap<>();
private final Map commandMap = new HashMap<>();
@@ -311,6 +313,14 @@ public class PluginManager
*/
public void registerListener(Plugin plugin, Listener listener)
{
+ for ( Method method : listener.getClass().getDeclaredMethods() )
+ {
+ if ( method.isAnnotationPresent( Subscribe.class ) )
+ {
+ proxy.getLogger().log( Level.SEVERE, "Listener {0} has registered using depreceated subscribe annotation! Please advice author to update to @EventHadler", listener );
+ }
+ }
+
eventBus.register( listener );
}
}
diff --git a/event/pom.xml b/event/pom.xml
new file mode 100644
index 00000000..a21bbe23
--- /dev/null
+++ b/event/pom.xml
@@ -0,0 +1,29 @@
+
+
+ 4.0.0
+
+
+ net.md-5
+ bungeecord-parent
+ 1.5-SNAPSHOT
+ ../pom.xml
+
+
+ net.md-5
+ bungeecord-event
+ 1.5-SNAPSHOT
+ jar
+
+ BungeeCord-Event
+ Generic java event dispatching API intended for use with BungeeCord
+
+
+
+ junit
+ junit
+ 4.11
+ test
+
+
+
diff --git a/event/src/main/java/net/md_5/bungee/event/EventBus.java b/event/src/main/java/net/md_5/bungee/event/EventBus.java
new file mode 100644
index 00000000..94e154ea
--- /dev/null
+++ b/event/src/main/java/net/md_5/bungee/event/EventBus.java
@@ -0,0 +1,163 @@
+package net.md_5.bungee.event;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.text.MessageFormat;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class EventBus
+{
+
+ private final Map, Map