summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNathan Adams <dinnerbone@dinnerbone.com>2012-01-13 08:51:10 +0000
committerNathan Adams <dinnerbone@dinnerbone.com>2012-01-13 08:53:14 +0000
commitce4f4af087f55bed13c5821dd631b520a7286e8c (patch)
treee7d84ec7d0bc88f1dd04757379fb9fa158b35341
parent389d70dbe2279253cf5ea5fcb97a6ed894f9e426 (diff)
downloadbukkit-ce4f4af087f55bed13c5821dd631b520a7286e8c.tar
bukkit-ce4f4af087f55bed13c5821dd631b520a7286e8c.tar.gz
bukkit-ce4f4af087f55bed13c5821dd631b520a7286e8c.tar.lz
bukkit-ce4f4af087f55bed13c5821dd631b520a7286e8c.tar.xz
bukkit-ce4f4af087f55bed13c5821dd631b520a7286e8c.zip
Implemented new Plugin Message API - see http://dinnerbone.com/blog/2012/01/13/minecraft-plugin-channels-messaging/
-rw-r--r--src/main/java/org/bukkit/Bukkit.java5
-rw-r--r--src/main/java/org/bukkit/Server.java11
-rw-r--r--src/main/java/org/bukkit/World.java3
-rw-r--r--src/main/java/org/bukkit/entity/Player.java3
-rw-r--r--src/main/java/org/bukkit/plugin/PluginManager.java1
-rw-r--r--src/main/java/org/bukkit/plugin/messaging/ChannelNameTooLongException.java14
-rw-r--r--src/main/java/org/bukkit/plugin/messaging/ChannelNotRegisteredException.java14
-rw-r--r--src/main/java/org/bukkit/plugin/messaging/MessageTooLargeException.java22
-rw-r--r--src/main/java/org/bukkit/plugin/messaging/Messenger.java201
-rw-r--r--src/main/java/org/bukkit/plugin/messaging/PluginChannelDirection.java16
-rw-r--r--src/main/java/org/bukkit/plugin/messaging/PluginMessageListener.java19
-rw-r--r--src/main/java/org/bukkit/plugin/messaging/PluginMessageListenerRegistration.java103
-rw-r--r--src/main/java/org/bukkit/plugin/messaging/PluginMessageRecipient.java32
-rw-r--r--src/main/java/org/bukkit/plugin/messaging/ReservedChannelException.java14
-rw-r--r--src/main/java/org/bukkit/plugin/messaging/StandardMessenger.java476
-rw-r--r--src/test/java/org/bukkit/plugin/messaging/StandardMessengerTest.java288
-rw-r--r--src/test/java/org/bukkit/plugin/messaging/TestMessageListener.java29
-rw-r--r--src/test/java/org/bukkit/plugin/messaging/TestPlayer.java605
-rw-r--r--src/test/java/org/bukkit/plugin/messaging/TestPlugin.java116
19 files changed, 1969 insertions, 3 deletions
diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java
index d7753329..739c6099 100644
--- a/src/main/java/org/bukkit/Bukkit.java
+++ b/src/main/java/org/bukkit/Bukkit.java
@@ -17,6 +17,7 @@ import org.bukkit.inventory.Recipe;
import org.bukkit.map.MapView;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.ServicesManager;
+import org.bukkit.plugin.messaging.Messenger;
import org.bukkit.scheduler.BukkitScheduler;
/**
@@ -286,4 +287,8 @@ public final class Bukkit {
public static File getWorldContainer() {
return server.getWorldContainer();
}
+
+ public static Messenger getMessenger() {
+ return server.getMessenger();
+ }
}
diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java
index 54f301e3..6c78def2 100644
--- a/src/main/java/org/bukkit/Server.java
+++ b/src/main/java/org/bukkit/Server.java
@@ -20,12 +20,14 @@ import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.map.MapView;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.ServicesManager;
+import org.bukkit.plugin.messaging.Messenger;
+import org.bukkit.plugin.messaging.PluginMessageRecipient;
import org.bukkit.scheduler.BukkitScheduler;
/**
* Represents a server implementation
*/
-public interface Server {
+public interface Server extends PluginMessageRecipient {
/**
* Used for all administrative messages, such as an operator using a command.
*
@@ -533,4 +535,11 @@ public interface Server {
* @return Array containing all players
*/
public OfflinePlayer[] getOfflinePlayers();
+
+ /**
+ * Gets the {@link Messenger} responsible for this server.
+ *
+ * @return Messenger responsible for this server.
+ */
+ public Messenger getMessenger();
}
diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java
index d6ae084d..4e2e34bf 100644
--- a/src/main/java/org/bukkit/World.java
+++ b/src/main/java/org/bukkit/World.java
@@ -12,12 +12,13 @@ import org.bukkit.block.Block;
import org.bukkit.entity.*;
import org.bukkit.generator.BlockPopulator;
import org.bukkit.inventory.ItemStack;
+import org.bukkit.plugin.messaging.PluginMessageRecipient;
import org.bukkit.util.Vector;
/**
* Represents a world, which may contain entities, chunks and blocks
*/
-public interface World {
+public interface World extends PluginMessageRecipient {
/**
* Gets the {@link Block} at the given coordinates
diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java
index 8fbb9509..26b42dce 100644
--- a/src/main/java/org/bukkit/entity/Player.java
+++ b/src/main/java/org/bukkit/entity/Player.java
@@ -12,12 +12,13 @@ import org.bukkit.OfflinePlayer;
import org.bukkit.Statistic;
import org.bukkit.command.CommandSender;
import org.bukkit.map.MapView;
+import org.bukkit.plugin.messaging.PluginMessageRecipient;
/**
* Represents a player, connected or not
*
*/
-public interface Player extends HumanEntity, CommandSender, OfflinePlayer {
+public interface Player extends HumanEntity, CommandSender, OfflinePlayer, PluginMessageRecipient {
/**
* Gets the "friendly" name to display of this player. This may include color.
*
diff --git a/src/main/java/org/bukkit/plugin/PluginManager.java b/src/main/java/org/bukkit/plugin/PluginManager.java
index 7d7f1c2b..c70bc22b 100644
--- a/src/main/java/org/bukkit/plugin/PluginManager.java
+++ b/src/main/java/org/bukkit/plugin/PluginManager.java
@@ -8,6 +8,7 @@ import org.bukkit.event.Event.Priority;
import org.bukkit.event.Listener;
import org.bukkit.permissions.Permissible;
import org.bukkit.permissions.Permission;
+import org.bukkit.plugin.messaging.PluginMessageListener;
/**
* Handles all plugin management from the Server
diff --git a/src/main/java/org/bukkit/plugin/messaging/ChannelNameTooLongException.java b/src/main/java/org/bukkit/plugin/messaging/ChannelNameTooLongException.java
new file mode 100644
index 00000000..76e06fc1
--- /dev/null
+++ b/src/main/java/org/bukkit/plugin/messaging/ChannelNameTooLongException.java
@@ -0,0 +1,14 @@
+package org.bukkit.plugin.messaging;
+
+/**
+ * Thrown if a Plugin Channel is too long.
+ */
+public class ChannelNameTooLongException extends RuntimeException {
+ public ChannelNameTooLongException() {
+ super("Attempted to send a Plugin Message to a channel that was too large. The maximum length a channel may be is " + Messenger.MAX_CHANNEL_SIZE + " chars.");
+ }
+
+ public ChannelNameTooLongException(String channel) {
+ super("Attempted to send a Plugin Message to a channel that was too large. The maximum length a channel may be is " + Messenger.MAX_CHANNEL_SIZE + " chars (attempted " + channel.length() + " - '" + channel + ".");
+ }
+}
diff --git a/src/main/java/org/bukkit/plugin/messaging/ChannelNotRegisteredException.java b/src/main/java/org/bukkit/plugin/messaging/ChannelNotRegisteredException.java
new file mode 100644
index 00000000..a7a568e9
--- /dev/null
+++ b/src/main/java/org/bukkit/plugin/messaging/ChannelNotRegisteredException.java
@@ -0,0 +1,14 @@
+package org.bukkit.plugin.messaging;
+
+/**
+ * Thrown if a Plugin attempts to send a message on an unregistered channel.
+ */
+public class ChannelNotRegisteredException extends RuntimeException {
+ public ChannelNotRegisteredException() {
+ this("Attempted to send a plugin message through an unregistered channel.");
+ }
+
+ public ChannelNotRegisteredException(String channel) {
+ super("Attempted to send a plugin message through an unregistered channel ('" + channel + "'.");
+ }
+}
diff --git a/src/main/java/org/bukkit/plugin/messaging/MessageTooLargeException.java b/src/main/java/org/bukkit/plugin/messaging/MessageTooLargeException.java
new file mode 100644
index 00000000..3a195c05
--- /dev/null
+++ b/src/main/java/org/bukkit/plugin/messaging/MessageTooLargeException.java
@@ -0,0 +1,22 @@
+package org.bukkit.plugin.messaging;
+
+/**
+ * Thrown if a Plugin Message is sent that is too large to be sent.
+ */
+public class MessageTooLargeException extends RuntimeException {
+ public MessageTooLargeException() {
+ this("Attempted to send a plugin message that was too large. The maximum length a plugin message may be is " + Messenger.MAX_MESSAGE_SIZE + " bytes.");
+ }
+
+ public MessageTooLargeException(byte[] message) {
+ this(message.length);
+ }
+
+ public MessageTooLargeException(int length) {
+ this("Attempted to send a plugin message that was too large. The maximum length a plugin message may be is " + Messenger.MAX_MESSAGE_SIZE + " bytes (tried to send one that is " + length + " bytes long).");
+ }
+
+ public MessageTooLargeException(String msg) {
+ super(msg);
+ }
+}
diff --git a/src/main/java/org/bukkit/plugin/messaging/Messenger.java b/src/main/java/org/bukkit/plugin/messaging/Messenger.java
new file mode 100644
index 00000000..5083587e
--- /dev/null
+++ b/src/main/java/org/bukkit/plugin/messaging/Messenger.java
@@ -0,0 +1,201 @@
+package org.bukkit.plugin.messaging;
+
+import java.util.Set;
+import org.bukkit.entity.Player;
+import org.bukkit.plugin.Plugin;
+
+/**
+ * A class responsible for managing the registrations of plugin channels and their
+ * listeners.
+ */
+public interface Messenger {
+ /**
+ * Represents the largest size that an individual Plugin Message may be.
+ */
+ public static final int MAX_MESSAGE_SIZE = 32766;
+
+ /**
+ * Represents the largest size that a Plugin Channel may be.
+ */
+ public static final int MAX_CHANNEL_SIZE = 16;
+
+ /**
+ * Checks if the specified channel is a reserved name.
+ *
+ * @param channel Channel name to check.
+ * @return True if the channel is reserved, otherwise false.
+ * @throws IllegalArgumentException Thrown if channel is null.
+ */
+ public boolean isReservedChannel(String channel);
+
+ /**
+ * Registers the specific plugin to the requested outgoing plugin channel, allowing it
+ * to send messages through that channel to any clients.
+ *
+ * @param plugin Plugin that wishes to send messages through the channel.
+ * @param channel Channel to register.
+ * @throws IllegalArgumentException Thrown if plugin or channel is null.
+ */
+ public void registerOutgoingPluginChannel(Plugin plugin, String channel);
+
+ /**
+ * Unregisters the specific plugin from the requested outgoing plugin channel, no longer
+ * allowing it to send messages through that channel to any clients.
+ *
+ * @param plugin Plugin that no longer wishes to send messages through the channel.
+ * @param channel Channel to unregister.
+ * @throws IllegalArgumentException Thrown if plugin or channel is null.
+ */
+ public void unregisterOutgoingPluginChannel(Plugin plugin, String channel);
+
+ /**
+ * Unregisters the specific plugin from all outgoing plugin channels, no longer allowing
+ * it to send any plugin messages.
+ *
+ * @param plugin Plugin that no longer wishes to send plugin messages.
+ * @throws IllegalArgumentException Thrown if plugin is null.
+ */
+ public void unregisterOutgoingPluginChannel(Plugin plugin);
+
+ /**
+ * Registers the specific plugin for listening on the requested incoming plugin channel,
+ * allowing it to act upon any plugin messages.
+ *
+ * @param plugin Plugin that wishes to register to this channel.
+ * @param channel Channel to register.
+ * @param listener Listener to receive messages on.
+ * @returns The resulting registration that was made as a result of this method.
+ * @throws IllegalArgumentException Thrown if plugin, channel or listener is null, or the listener is already registered for this channel.
+ */
+ public PluginMessageListenerRegistration registerIncomingPluginChannel(Plugin plugin, String channel, PluginMessageListener listener);
+
+ /**
+ * Unregisters the specific plugin's listener from listening on the requested incoming plugin channel,
+ * no longer allowing it to act upon any plugin messages.
+ *
+ * @param plugin Plugin that wishes to unregister from this channel.
+ * @param channel Channel to unregister.
+ * @param listener Listener to stop receiving messages on.
+ * @throws IllegalArgumentException Thrown if plugin, channel or listener is null.
+ */
+ public void unregisterIncomingPluginChannel(Plugin plugin, String channel, PluginMessageListener listener);
+
+ /**
+ * Unregisters the specific plugin from listening on the requested incoming plugin channel,
+ * no longer allowing it to act upon any plugin messages.
+ *
+ * @param plugin Plugin that wishes to unregister from this channel.
+ * @param channel Channel to unregister.
+ * @throws IllegalArgumentException Thrown if plugin or channel is null.
+ */
+ public void unregisterIncomingPluginChannel(Plugin plugin, String channel);
+
+ /**
+ * Unregisters the specific plugin from listening on all plugin channels through all listeners.
+ *
+ * @param plugin Plugin that wishes to unregister from this channel.
+ * @throws IllegalArgumentException Thrown if plugin is null.
+ */
+ public void unregisterIncomingPluginChannel(Plugin plugin);
+
+ /**
+ * Gets a set containing all the outgoing plugin channels.
+ *
+ * @return List of all registered outgoing plugin channels.
+ */
+ public Set<String> getOutgoingChannels();
+
+ /**
+ * Gets a set containing all the outgoing plugin channels that the specified plugin is registered to.
+ *
+ * @param plugin Plugin to retrieve channels for.
+ * @return List of all registered outgoing plugin channels that a plugin is registered to.
+ * @throws IllegalArgumentException Thrown if plugin is null.
+ */
+ public Set<String> getOutgoingChannels(Plugin plugin);
+
+ /**
+ * Gets a set containing all the incoming plugin channels.
+ *
+ * @return List of all registered incoming plugin channels.
+ */
+ public Set<String> getIncomingChannels();
+
+ /**
+ * Gets a set containing all the incoming plugin channels that the specified plugin is registered for.
+ *
+ * @param plugin Plugin to retrieve channels for.
+ * @return List of all registered incoming plugin channels that the plugin is registered for.
+ * @throws IllegalArgumentException Thrown if plugin is null.
+ */
+ public Set<String> getIncomingChannels(Plugin plugin);
+
+ /**
+ * Gets a set containing all the incoming plugin channel registrations that the specified plugin has.
+ *
+ * @param plugin Plugin to retrieve registrations for.
+ * @return List of all registrations that the plugin has.
+ * @throws IllegalArgumentException Thrown if plugin is null.
+ */
+ public Set<PluginMessageListenerRegistration> getIncomingChannelRegistrations(Plugin plugin);
+
+ /**
+ * Gets a set containing all the incoming plugin channel registrations that are on the requested channel.
+ *
+ * @param channel Channel to retrieve registrations for.
+ * @return List of all registrations that are on the channel.
+ * @throws IllegalArgumentException Thrown if channel is null.
+ */
+ public Set<PluginMessageListenerRegistration> getIncomingChannelRegistrations(String channel);
+
+ /**
+ * Gets a set containing all the incoming plugin channel registrations that the specified plugin has
+ * on the requested channel.
+ *
+ * @param plugin Plugin to retrieve registrations for.
+ * @param channel Channel to filter registrations by.
+ * @return List of all registrations that the plugin has.
+ * @throws IllegalArgumentException Thrown if plugin or channel is null.
+ */
+ public Set<PluginMessageListenerRegistration> getIncomingChannelRegistrations(Plugin plugin, String channel);
+
+ /**
+ * Checks if the specified plugin message listener registration is valid.
+ * <p>
+ * A registration is considered valid if it has not be unregistered and that the plugin
+ * is still enabled.
+ *
+ * @param registration Registration to check.
+ * @return True if the registration is valid, otherwise false.
+ */
+ public boolean isRegistrationValid(PluginMessageListenerRegistration registration);
+
+ /**
+ * Checks if the specified plugin has registered to receive incoming messages through the requested
+ * channel.
+ *
+ * @param plugin Plugin to check registration for.
+ * @param channel Channel to test for.
+ * @return True if the channel is registered, else false.
+ */
+ public boolean isIncomingChannelRegistered(Plugin plugin, String channel);
+
+ /**
+ * Checks if the specified plugin has registered to send outgoing messages through the requested
+ * channel.
+ *
+ * @param plugin Plugin to check registration for.
+ * @param channel Channel to test for.
+ * @return True if the channel is registered, else false.
+ */
+ public boolean isOutgoingChannelRegistered(Plugin plugin, String channel);
+
+ /**
+ * Dispatches the specified incoming message to any registered listeners.
+ *
+ * @param source Source of the message.
+ * @param channel Channel that the message was sent by.
+ * @param message Raw payload of the message.
+ */
+ public void dispatchIncomingMessage(Player source, String channel, byte[] message);
+}
diff --git a/src/main/java/org/bukkit/plugin/messaging/PluginChannelDirection.java b/src/main/java/org/bukkit/plugin/messaging/PluginChannelDirection.java
new file mode 100644
index 00000000..3b385484
--- /dev/null
+++ b/src/main/java/org/bukkit/plugin/messaging/PluginChannelDirection.java
@@ -0,0 +1,16 @@
+package org.bukkit.plugin.messaging;
+
+/**
+ * Represents the different directions a plugin channel may go.
+ */
+public enum PluginChannelDirection {
+ /**
+ * The plugin channel is being sent to the server from a client.
+ */
+ INCOMING,
+
+ /**
+ * The plugin channel is being sent to a client from the server.
+ */
+ OUTGOING
+}
diff --git a/src/main/java/org/bukkit/plugin/messaging/PluginMessageListener.java b/src/main/java/org/bukkit/plugin/messaging/PluginMessageListener.java
new file mode 100644
index 00000000..0e197a6d
--- /dev/null
+++ b/src/main/java/org/bukkit/plugin/messaging/PluginMessageListener.java
@@ -0,0 +1,19 @@
+package org.bukkit.plugin.messaging;
+
+import org.bukkit.entity.Player;
+
+/**
+ * A listener for a specific Plugin Channel, which will receive notifications of messages sent
+ * from a client.
+ */
+public interface PluginMessageListener {
+ /**
+ * A method that will be thrown when a {@link PluginMessageSource} sends a plugin
+ * message on a registered channel.
+ *
+ * @param channel Channel that the message was sent through.
+ * @param player Source of the message.
+ * @param message The raw message that was sent.
+ */
+ public void onPluginMessageReceived(String channel, Player player, byte[] message);
+}
diff --git a/src/main/java/org/bukkit/plugin/messaging/PluginMessageListenerRegistration.java b/src/main/java/org/bukkit/plugin/messaging/PluginMessageListenerRegistration.java
new file mode 100644
index 00000000..f736ce99
--- /dev/null
+++ b/src/main/java/org/bukkit/plugin/messaging/PluginMessageListenerRegistration.java
@@ -0,0 +1,103 @@
+package org.bukkit.plugin.messaging;
+
+import org.bukkit.plugin.Plugin;
+
+/**
+ * Contains information about a {@link Plugin}s registration to a plugin channel.
+ */
+public final class PluginMessageListenerRegistration {
+ private final Messenger messenger;
+ private final Plugin plugin;
+ private final String channel;
+ private final PluginMessageListener listener;
+
+ public PluginMessageListenerRegistration(Messenger messenger, Plugin plugin, String channel, PluginMessageListener listener) {
+ if (messenger == null) {
+ throw new IllegalArgumentException("Messenger cannot be null!");
+ }
+ if (plugin == null) {
+ throw new IllegalArgumentException("Plugin cannot be null!");
+ }
+ if (channel == null) {
+ throw new IllegalArgumentException("Channel cannot be null!");
+ }
+ if (listener == null) {
+ throw new IllegalArgumentException("Listener cannot be null!");
+ }
+
+ this.messenger = messenger;
+ this.plugin = plugin;
+ this.channel = channel;
+ this.listener = listener;
+ }
+
+ /**
+ * Gets the plugin channel that this registration is about.
+ *
+ * @return Plugin channel.
+ */
+ public String getChannel() {
+ return channel;
+ }
+
+ /**
+ * Gets the registered listener described by this registration.
+ *
+ * @return Registered listener.
+ */
+ public PluginMessageListener getListener() {
+ return listener;
+ }
+
+ /**
+ * Gets the plugin that this registration is for.
+ *
+ * @return Registered plugin.
+ */
+ public Plugin getPlugin() {
+ return plugin;
+ }
+
+ /**
+ * Checks if this registration is still valid.
+ *
+ * @return True if this registration is still valid, otherwise false.
+ */
+ public boolean isValid() {
+ return messenger.isRegistrationValid(this);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final PluginMessageListenerRegistration other = (PluginMessageListenerRegistration) obj;
+ if (this.messenger != other.messenger && (this.messenger == null || !this.messenger.equals(other.messenger))) {
+ return false;
+ }
+ if (this.plugin != other.plugin && (this.plugin == null || !this.plugin.equals(other.plugin))) {
+ return false;
+ }
+ if ((this.channel == null) ? (other.channel != null) : !this.channel.equals(other.channel)) {
+ return false;
+ }
+ if (this.listener != other.listener && (this.listener == null || !this.listener.equals(other.listener))) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 7;
+ hash = 53 * hash + (this.messenger != null ? this.messenger.hashCode() : 0);
+ hash = 53 * hash + (this.plugin != null ? this.plugin.hashCode() : 0);
+ hash = 53 * hash + (this.channel != null ? this.channel.hashCode() : 0);
+ hash = 53 * hash + (this.listener != null ? this.listener.hashCode() : 0);
+ return hash;
+ }
+}
diff --git a/src/main/java/org/bukkit/plugin/messaging/PluginMessageRecipient.java b/src/main/java/org/bukkit/plugin/messaging/PluginMessageRecipient.java
new file mode 100644
index 00000000..6383166b
--- /dev/null
+++ b/src/main/java/org/bukkit/plugin/messaging/PluginMessageRecipient.java
@@ -0,0 +1,32 @@
+package org.bukkit.plugin.messaging;
+
+import java.util.Set;
+import org.bukkit.plugin.Plugin;
+
+/**
+ * Represents a possible recipient for a Plugin Message.
+ */
+public interface PluginMessageRecipient {
+ /**
+ * Sends this recipient a Plugin Message on the specified outgoing channel.
+ * <p>
+ * The message may not be larger than {@link Messenger#MAX_MESSAGE_SIZE} bytes, and the plugin must be registered to send
+ * messages on the specified channel.
+ *
+ * @param source The plugin that sent this message.
+ * @param channel The channel to send this message on.
+ * @param message The raw message to send.
+ * @throws IllegalArgumentException Thrown if the source plugin is disabled.
+ * @throws IllegalArgumentException Thrown if source, channel or message is null.
+ * @throws MessageTooLargeException Thrown if the message is too big.
+ * @throws ChannelNotRegisteredException Thrown if the channel is not registered for this plugin.
+ */
+ public void sendPluginMessage(Plugin source, String channel, byte[] message);
+
+ /**
+ * Gets a set containing all the Plugin Channels that this client is listening on.
+ *
+ * @return Set containing all the channels that this client may accept.
+ */
+ public Set<String> getListeningPluginChannels();
+}
diff --git a/src/main/java/org/bukkit/plugin/messaging/ReservedChannelException.java b/src/main/java/org/bukkit/plugin/messaging/ReservedChannelException.java
new file mode 100644
index 00000000..8b20b41a
--- /dev/null
+++ b/src/main/java/org/bukkit/plugin/messaging/ReservedChannelException.java
@@ -0,0 +1,14 @@
+package org.bukkit.plugin.messaging;
+
+/**
+ * Thrown if a plugin attempts to register for a reserved channel (such as "REGISTER")
+ */
+public class ReservedChannelException extends RuntimeException {
+ public ReservedChannelException() {
+ this("Attempted to register for a reserved channel name.");
+ }
+
+ public ReservedChannelException(String name) {
+ super("Attempted to register for a reserved channel name ('" + name + "')");
+ }
+}
diff --git a/src/main/java/org/bukkit/plugin/messaging/StandardMessenger.java b/src/main/java/org/bukkit/plugin/messaging/StandardMessenger.java
new file mode 100644
index 00000000..e8ff0840
--- /dev/null
+++ b/src/main/java/org/bukkit/plugin/messaging/StandardMessenger.java
@@ -0,0 +1,476 @@
+package org.bukkit.plugin.messaging;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSet.Builder;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import org.bukkit.entity.Player;
+import org.bukkit.plugin.Plugin;
+
+/**
+ * Standard implementation to {@link Messenger}
+ */
+public class StandardMessenger implements Messenger {
+ private final Map<String, Set<PluginMessageListenerRegistration>> incomingByChannel = new HashMap<String, Set<PluginMessageListenerRegistration>>();
+ private final Map<Plugin, Set<PluginMessageListenerRegistration>> incomingByPlugin = new HashMap<Plugin, Set<PluginMessageListenerRegistration>>();
+ private final Map<String, Set<Plugin>> outgoingByChannel = new HashMap<String, Set<Plugin>>();
+ private final Map<Plugin, Set<String>> outgoingByPlugin = new HashMap<Plugin, Set<String>>();
+ private final Object incomingLock = new Object();
+ private final Object outgoingLock = new Object();
+
+ private void addToOutgoing(Plugin plugin, String channel) {
+ synchronized (outgoingLock) {
+ Set<Plugin> plugins = outgoingByChannel.get(channel);
+ Set<String> channels = outgoingByPlugin.get(plugin);
+
+ if (plugins == null) {
+ plugins = new HashSet<Plugin>();
+ outgoingByChannel.put(channel, plugins);
+ }
+
+ if (channels == null) {
+ channels = new HashSet<String>();
+ outgoingByPlugin.put(plugin, channels);
+ }
+
+ plugins.add(plugin);
+ channels.add(channel);
+ }
+ }
+
+ private void removeFromOutgoing(Plugin plugin, String channel) {
+ synchronized (outgoingLock) {
+ Set<Plugin> plugins = outgoingByChannel.get(channel);
+ Set<String> channels = outgoingByPlugin.get(plugin);
+
+ if (plugins != null) {
+ plugins.remove(plugin);
+
+ if (plugins.isEmpty()) {
+ outgoingByChannel.remove(channel);
+ }
+ }
+
+ if (channels != null) {
+ channels.remove(channel);
+
+ if (channels.isEmpty()) {
+ outgoingByChannel.remove(channel);
+ }
+ }
+ }
+ }
+
+ private void removeFromOutgoing(Plugin plugin) {
+ synchronized (outgoingLock) {
+ Set<String> channels = outgoingByPlugin.get(plugin);
+
+ if (channels != null) {
+ String[] toRemove = channels.toArray(new String[0]);
+
+ outgoingByPlugin.remove(plugin);
+
+ for (String channel : toRemove) {
+ removeFromOutgoing(plugin, channel);
+ }
+ }
+ }
+ }
+
+ private void addToIncoming(PluginMessageListenerRegistration registration) {
+ synchronized (incomingLock) {
+ Set<PluginMessageListenerRegistration> registrations = incomingByChannel.get(registration.getChannel());
+
+ if (registrations == null) {
+ registrations = new HashSet<PluginMessageListenerRegistration>();
+ incomingByChannel.put(registration.getChannel(), registrations);
+ } else {
+ if (registrations.contains(registration)) {
+ throw new IllegalArgumentException("This registration already exists");
+ }
+ }
+
+ registrations.add(registration);
+
+ registrations = incomingByPlugin.get(registration.getPlugin());
+
+ if (registrations == null) {
+ registrations = new HashSet<PluginMessageListenerRegistration>();
+ incomingByPlugin.put(registration.getPlugin(), registrations);
+ } else {
+ if (registrations.contains(registration)) {
+ throw new IllegalArgumentException("This registration already exists");
+ }
+ }
+
+ registrations.add(registration);
+ }
+ }
+
+ private void removeFromIncoming(PluginMessageListenerRegistration registration) {
+ synchronized (incomingLock) {
+ Set<PluginMessageListenerRegistration> registrations = incomingByChannel.get(registration.getChannel());
+
+ if (registrations != null) {
+ registrations.remove(registration);
+
+ if (registrations.isEmpty()) {
+ incomingByChannel.remove(registration.getChannel());
+ }
+ }
+
+ registrations = incomingByPlugin.get(registration.getPlugin());
+
+ if (registrations != null) {
+ registrations.remove(registration);
+
+ if (registrations.isEmpty()) {
+ incomingByPlugin.remove(registration.getPlugin());
+ }
+ }
+ }
+ }
+
+ private void removeFromIncoming(Plugin plugin, String channel) {
+ synchronized (incomingLock) {
+ Set<PluginMessageListenerRegistration> registrations = incomingByPlugin.get(plugin);
+
+ if (registrations != null) {
+ PluginMessageListenerRegistration[] toRemove = registrations.toArray(new PluginMessageListenerRegistration[0]);
+
+ for (PluginMessageListenerRegistration registration : toRemove) {
+ if (registration.getChannel().equals(channel)) {
+ removeFromIncoming(registration);
+ }
+ }
+ }
+ }
+ }
+
+ private void removeFromIncoming(Plugin plugin) {
+ synchronized (incomingLock) {
+ Set<PluginMessageListenerRegistration> registrations = incomingByPlugin.get(plugin);
+
+ if (registrations != null) {
+ PluginMessageListenerRegistration[] toRemove = registrations.toArray(new PluginMessageListenerRegistration[0]);
+
+ incomingByPlugin.remove(plugin);
+
+ for (PluginMessageListenerRegistration registration : toRemove) {
+ removeFromIncoming(registration);
+ }
+ }
+ }
+ }
+
+ public boolean isReservedChannel(String channel) {
+ validateChannel(channel);
+
+ return channel.equals("REGISTER") || channel.equals("UNREGISTER");
+ }
+
+ public void registerOutgoingPluginChannel(Plugin plugin, String channel) {
+ if (plugin == null) {
+ throw new IllegalArgumentException("Plugin cannot be null");
+ }
+ validateChannel(channel);
+ if (isReservedChannel(channel)) {
+ throw new ReservedChannelException(channel);
+ }
+
+ addToOutgoing(plugin, channel);
+ }
+
+ public void unregisterOutgoingPluginChannel(Plugin plugin, String channel) {
+ if (plugin == null) {
+ throw new IllegalArgumentException("Plugin cannot be null");
+ }
+ validateChannel(channel);
+
+ removeFromOutgoing(plugin, channel);
+ }
+
+ public void unregisterOutgoingPluginChannel(Plugin plugin) {
+ if (plugin == null) {
+ throw new IllegalArgumentException("Plugin cannot be null");
+ }
+
+ removeFromOutgoing(plugin);
+ }
+
+ public PluginMessageListenerRegistration registerIncomingPluginChannel(Plugin plugin, String channel, PluginMessageListener listener) {
+ if (plugin == null) {
+ throw new IllegalArgumentException("Plugin cannot be null");
+ }
+ validateChannel(channel);
+ if (isReservedChannel(channel)) {
+ throw new ReservedChannelException(channel);
+ }
+ if (listener == null) {
+ throw new IllegalArgumentException("Listener cannot be null");
+ }
+
+ PluginMessageListenerRegistration result = new PluginMessageListenerRegistration(this, plugin, channel, listener);
+
+ addToIncoming(result);
+
+ return result;
+ }
+
+ public void unregisterIncomingPluginChannel(Plugin plugin, String channel, PluginMessageListener listener) {
+ if (plugin == null) {
+ throw new IllegalArgumentException("Plugin cannot be null");
+ }
+ if (listener == null) {
+ throw new IllegalArgumentException("Listener cannot be null");
+ }
+ validateChannel(channel);
+
+ removeFromIncoming(new PluginMessageListenerRegistration(this, plugin, channel, listener));
+ }
+
+ public void unregisterIncomingPluginChannel(Plugin plugin, String channel) {
+ if (plugin == null) {
+ throw new IllegalArgumentException("Plugin cannot be null");
+ }
+ validateChannel(channel);
+
+ removeFromIncoming(plugin, channel);
+ }
+
+ public void unregisterIncomingPluginChannel(Plugin plugin) {
+ if (plugin == null) {
+ throw new IllegalArgumentException("Plugin cannot be null");
+ }
+
+ removeFromIncoming(plugin);
+ }
+
+ public Set<String> getOutgoingChannels() {
+ synchronized (outgoingLock) {
+ Set<String> keys = outgoingByChannel.keySet();
+ return ImmutableSet.copyOf(keys);
+ }
+ }
+
+ public Set<String> getOutgoingChannels(Plugin plugin) {
+ if (plugin == null) {
+ throw new IllegalArgumentException("Plugin cannot be null");
+ }
+
+ synchronized (outgoingLock) {
+ Set<String> channels = outgoingByPlugin.get(plugin);
+
+ if (channels != null) {
+ return ImmutableSet.copyOf(channels);
+ } else {
+ return ImmutableSet.of();
+ }
+ }
+ }
+
+ public Set<String> getIncomingChannels() {
+ synchronized (incomingLock) {
+ Set<String> keys = incomingByChannel.keySet();
+ return ImmutableSet.copyOf(keys);
+ }
+ }
+
+ public Set<String> getIncomingChannels(Plugin plugin) {
+ if (plugin == null) {
+ throw new IllegalArgumentException("Plugin cannot be null");
+ }
+
+ synchronized (incomingLock) {
+ Set<PluginMessageListenerRegistration> registrations = incomingByPlugin.get(plugin);
+
+ if (registrations != null) {
+ Builder<String> builder = ImmutableSet.builder();
+
+ for (PluginMessageListenerRegistration registration : registrations) {
+ builder.add(registration.getChannel());
+ }
+
+ return builder.build();
+ } else {
+ return ImmutableSet.of();
+ }
+ }
+ }
+
+ public Set<PluginMessageListenerRegistration> getIncomingChannelRegistrations(Plugin plugin) {
+ if (plugin == null) {
+ throw new IllegalArgumentException("Plugin cannot be null");
+ }
+
+ synchronized (incomingLock) {
+ Set<PluginMessageListenerRegistration> registrations = incomingByPlugin.get(plugin);
+
+ if (registrations != null) {
+ return ImmutableSet.copyOf(registrations);
+ } else {
+ return ImmutableSet.of();
+ }
+ }
+ }
+
+ public Set<PluginMessageListenerRegistration> getIncomingChannelRegistrations(String channel) {
+ validateChannel(channel);
+
+ synchronized (incomingLock) {
+ Set<PluginMessageListenerRegistration> registrations = incomingByChannel.get(channel);
+
+ if (registrations != null) {
+ return ImmutableSet.copyOf(registrations);
+ } else {
+ return ImmutableSet.of();
+ }
+ }
+ }
+
+ public Set<PluginMessageListenerRegistration> getIncomingChannelRegistrations(Plugin plugin, String channel) {
+ if (plugin == null) {
+ throw new IllegalArgumentException("Plugin cannot be null");
+ }
+ validateChannel(channel);
+
+ synchronized (incomingLock) {
+ Set<PluginMessageListenerRegistration> registrations = incomingByPlugin.get(plugin);
+
+ if (registrations != null) {
+ Builder<PluginMessageListenerRegistration> builder = ImmutableSet.builder();
+
+ for (PluginMessageListenerRegistration registration : registrations) {
+ if (registration.getChannel().equals(channel)) {
+ builder.add(registration);
+ }
+ }
+
+ return builder.build();
+ } else {
+ return ImmutableSet.of();
+ }
+ }
+ }
+
+ public boolean isRegistrationValid(PluginMessageListenerRegistration registration) {
+ if (registration == null) {
+ throw new IllegalArgumentException("Registration cannot be null");
+ }
+
+ synchronized (incomingLock) {
+ Set<PluginMessageListenerRegistration> registrations = incomingByPlugin.get(registration.getPlugin());
+
+ if (registrations != null) {
+ return registrations.contains(registration);
+ }
+
+ return false;
+ }
+ }
+
+ public boolean isIncomingChannelRegistered(Plugin plugin, String channel) {
+ if (plugin == null) {
+ throw new IllegalArgumentException("Plugin cannot be null");
+ }
+ validateChannel(channel);
+
+ synchronized (incomingLock) {
+ Set<PluginMessageListenerRegistration> registrations = incomingByPlugin.get(plugin);
+
+ if (registrations != null) {
+ for (PluginMessageListenerRegistration registration : registrations) {
+ if (registration.getChannel().equals(channel)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+ }
+
+ public boolean isOutgoingChannelRegistered(Plugin plugin, String channel) {
+ if (plugin == null) {
+ throw new IllegalArgumentException("Plugin cannot be null");
+ }
+ validateChannel(channel);
+
+ synchronized (outgoingLock) {
+ Set<String> channels = outgoingByPlugin.get(plugin);
+
+ if (channels != null) {
+ return channels.contains(channel);
+ }
+
+ return false;
+ }
+ }
+
+ public void dispatchIncomingMessage(Player source, String channel, byte[] message) {
+ if (source == null) {
+ throw new IllegalArgumentException("Player source cannot be null");
+ }
+ if (message == null) {
+ throw new IllegalArgumentException("Message cannot be null");
+ }
+ validateChannel(channel);
+
+ Set<PluginMessageListenerRegistration> registrations = getIncomingChannelRegistrations(channel);
+
+ for (PluginMessageListenerRegistration registration : registrations) {
+ registration.getListener().onPluginMessageReceived(channel, source, message);
+ }
+ }
+
+ /**
+ * Validates a Plugin Channel name.
+ *
+ * @param channel Channel name to validate.
+ */
+ public static void validateChannel(String channel) {
+ if (channel == null) {
+ throw new IllegalArgumentException("Channel cannot be null");
+ }
+ if (channel.length() > Messenger.MAX_CHANNEL_SIZE) {
+ throw new ChannelNameTooLongException(channel);
+ }
+ }
+
+ /**
+ * Validates the input of a Plugin Message, ensuring the arguments are all valid.
+ *
+ * @param messenger Messenger to use for validation.
+ * @param source Source plugin of the Message.
+ * @param channel Plugin Channel to send the message by.
+ * @param message Raw message payload to send.
+ * @throws IllegalArgumentException Thrown if the source plugin is disabled.
+ * @throws IllegalArgumentException Thrown if source, channel or message is null.
+ * @throws MessageTooLargeException Thrown if the message is too big.
+ * @throws ChannelNameTooLongException Thrown if the channel name is too long.
+ * @throws ChannelNotRegisteredException Thrown if the channel is not registered for this plugin.
+ */
+ public static void validatePluginMessage(Messenger messenger, Plugin source, String channel, byte[] message) {
+ if (messenger == null) {
+ throw new IllegalArgumentException("Messenger cannot be null");
+ }
+ if (source == null) {
+ throw new IllegalArgumentException("Plugin source cannot be null");
+ }
+ if (!source.isEnabled()) {
+ throw new IllegalArgumentException("Plugin must be enabled to send messages");
+ }
+ if (message == null) {
+ throw new IllegalArgumentException("Message cannot be null");
+ }
+ if (!messenger.isOutgoingChannelRegistered(source, channel)) {
+ throw new ChannelNotRegisteredException(channel);
+ }
+ if (message.length > Messenger.MAX_MESSAGE_SIZE) {
+ throw new MessageTooLargeException(message);
+ }
+ validateChannel(channel);
+ }
+}
diff --git a/src/test/java/org/bukkit/plugin/messaging/StandardMessengerTest.java b/src/test/java/org/bukkit/plugin/messaging/StandardMessengerTest.java
new file mode 100644
index 00000000..abf85427
--- /dev/null
+++ b/src/test/java/org/bukkit/plugin/messaging/StandardMessengerTest.java
@@ -0,0 +1,288 @@
+package org.bukkit.plugin.messaging;
+
+import org.bukkit.plugin.messaging.ReservedChannelException;
+import java.util.Collection;
+import org.junit.Test;
+import static org.junit.Assert.*;
+import static org.hamcrest.CoreMatchers.*;
+import static org.junit.matchers.JUnitMatchers.*;
+
+public class StandardMessengerTest {
+ public StandardMessenger getMessenger() {
+ return new StandardMessenger();
+ }
+
+ public TestPlugin getPlugin() {
+ return new TestPlugin();
+ }
+
+ @Test
+ public void testIsReservedChannel() {
+ Messenger messenger = getMessenger();
+
+ assertTrue(messenger.isReservedChannel("REGISTER"));
+ assertFalse(messenger.isReservedChannel("register"));
+ assertTrue(messenger.isReservedChannel("UNREGISTER"));
+ assertFalse(messenger.isReservedChannel("unregister"));
+ assertFalse(messenger.isReservedChannel("notReserved"));
+ }
+
+ @Test
+ public void testRegisterAndUnregisterOutgoingPluginChannel() {
+ Messenger messenger = getMessenger();
+ TestPlugin plugin = getPlugin();
+
+ assertFalse(messenger.isOutgoingChannelRegistered(plugin, "foo"));
+ messenger.registerOutgoingPluginChannel(plugin, "foo");
+ assertTrue(messenger.isOutgoingChannelRegistered(plugin, "foo"));
+ assertFalse(messenger.isOutgoingChannelRegistered(plugin, "bar"));
+
+ messenger.unregisterOutgoingPluginChannel(plugin, "foo");
+ assertFalse(messenger.isOutgoingChannelRegistered(plugin, "foo"));
+ }
+
+ @Test(expected=ReservedChannelException.class)
+ public void testReservedOutgoingRegistration() {
+ Messenger messenger = getMessenger();
+ TestPlugin plugin = getPlugin();
+
+ messenger.registerOutgoingPluginChannel(plugin, "REGISTER");
+ }
+
+ @Test
+ public void testUnregisterOutgoingPluginChannel_Plugin() {
+ Messenger messenger = getMessenger();
+ TestPlugin plugin = getPlugin();
+
+ assertFalse(messenger.isOutgoingChannelRegistered(plugin, "foo"));
+ messenger.registerOutgoingPluginChannel(plugin, "foo");
+ messenger.registerOutgoingPluginChannel(plugin, "bar");
+ assertTrue(messenger.isOutgoingChannelRegistered(plugin, "foo"));
+ assertTrue(messenger.isOutgoingChannelRegistered(plugin, "bar"));
+
+ messenger.unregisterOutgoingPluginChannel(plugin);
+ assertFalse(messenger.isOutgoingChannelRegistered(plugin, "foo"));
+ assertFalse(messenger.isOutgoingChannelRegistered(plugin, "bar"));
+ }
+
+ @Test
+ public void testRegisterIncomingPluginChannel() {
+ Messenger messenger = getMessenger();
+ TestPlugin plugin = getPlugin();
+ TestMessageListener listener = new TestMessageListener("foo", "bar".getBytes());
+ TestPlayer player = new TestPlayer();
+ PluginMessageListenerRegistration registration = messenger.registerIncomingPluginChannel(plugin, "foo", listener);
+
+ assertTrue(registration.isValid());
+ assertTrue(messenger.isIncomingChannelRegistered(plugin, "foo"));
+ messenger.dispatchIncomingMessage(player, "foo", "bar".getBytes());
+ assertTrue(listener.hasReceived());
+
+ messenger.unregisterIncomingPluginChannel(plugin, "foo", listener);
+ listener.reset();
+
+ assertFalse(registration.isValid());
+ assertFalse(messenger.isIncomingChannelRegistered(plugin, "foo"));
+ messenger.dispatchIncomingMessage(player, "foo", "bar".getBytes());
+ assertFalse(listener.hasReceived());
+ }
+
+ @Test(expected=ReservedChannelException.class)
+ public void testReservedIncomingRegistration() {
+ Messenger messenger = getMessenger();
+ TestPlugin plugin = getPlugin();
+
+ messenger.registerIncomingPluginChannel(plugin, "REGISTER", new TestMessageListener("foo", "bar".getBytes()));
+ }
+
+ @Test(expected=IllegalArgumentException.class)
+ public void testDuplicateIncomingRegistration() {
+ Messenger messenger = getMessenger();
+ TestPlugin plugin = getPlugin();
+ TestMessageListener listener = new TestMessageListener("foo", "bar".getBytes());
+
+ messenger.registerIncomingPluginChannel(plugin, "baz", listener);
+ messenger.registerIncomingPluginChannel(plugin, "baz", listener);
+ }
+
+ @Test
+ public void testUnregisterIncomingPluginChannel_Plugin_String() {
+ Messenger messenger = getMessenger();
+ TestPlugin plugin = getPlugin();
+ TestMessageListener listener1 = new TestMessageListener("foo", "bar".getBytes());
+ TestMessageListener listener2 = new TestMessageListener("baz", "qux".getBytes());
+ TestPlayer player = new TestPlayer();
+ PluginMessageListenerRegistration registration1 = messenger.registerIncomingPluginChannel(plugin, "foo", listener1);
+ PluginMessageListenerRegistration registration2 = messenger.registerIncomingPluginChannel(plugin, "baz", listener2);
+
+ assertTrue(registration1.isValid());
+ assertTrue(registration2.isValid());
+ messenger.dispatchIncomingMessage(player, "foo", "bar".getBytes());
+ messenger.dispatchIncomingMessage(player, "baz", "qux".getBytes());
+ assertTrue(listener1.hasReceived());
+ assertTrue(listener2.hasReceived());
+
+ messenger.unregisterIncomingPluginChannel(plugin, "foo");
+ listener1.reset();
+ listener2.reset();
+
+ assertFalse(registration1.isValid());
+ assertTrue(registration2.isValid());
+ messenger.dispatchIncomingMessage(player, "foo", "bar".getBytes());
+ messenger.dispatchIncomingMessage(player, "baz", "qux".getBytes());
+ assertFalse(listener1.hasReceived());
+ assertTrue(listener2.hasReceived());
+ }
+
+ @Test
+ public void testUnregisterIncomingPluginChannel_Plugin() {
+ Messenger messenger = getMessenger();
+ TestPlugin plugin = getPlugin();
+ TestMessageListener listener1 = new TestMessageListener("foo", "bar".getBytes());
+ TestMessageListener listener2 = new TestMessageListener("baz", "qux".getBytes());
+ TestPlayer player = new TestPlayer();
+ PluginMessageListenerRegistration registration1 = messenger.registerIncomingPluginChannel(plugin, "foo", listener1);
+ PluginMessageListenerRegistration registration2 = messenger.registerIncomingPluginChannel(plugin, "baz", listener2);
+
+ assertTrue(registration1.isValid());
+ assertTrue(registration2.isValid());
+ messenger.dispatchIncomingMessage(player, "foo", "bar".getBytes());
+ messenger.dispatchIncomingMessage(player, "baz", "qux".getBytes());
+ assertTrue(listener1.hasReceived());
+ assertTrue(listener2.hasReceived());
+
+ messenger.unregisterIncomingPluginChannel(plugin);
+ listener1.reset();
+ listener2.reset();
+
+ assertFalse(registration1.isValid());
+ assertFalse(registration2.isValid());
+ messenger.dispatchIncomingMessage(player, "foo", "bar".getBytes());
+ messenger.dispatchIncomingMessage(player, "baz", "qux".getBytes());
+ assertFalse(listener1.hasReceived());
+ assertFalse(listener2.hasReceived());
+ }
+
+ @Test
+ public void testGetOutgoingChannels() {
+ Messenger messenger = getMessenger();
+ TestPlugin plugin1 = getPlugin();
+ TestPlugin plugin2 = getPlugin();
+
+ assertEquals(messenger.getOutgoingChannels());
+
+ messenger.registerOutgoingPluginChannel(plugin1, "foo");
+ messenger.registerOutgoingPluginChannel(plugin1, "bar");
+ messenger.registerOutgoingPluginChannel(plugin2, "baz");
+ messenger.registerOutgoingPluginChannel(plugin2, "baz");
+
+ assertEquals(messenger.getOutgoingChannels(), "foo", "bar", "baz");
+ }
+
+ @Test
+ public void testGetOutgoingChannels_Plugin() {
+ Messenger messenger = getMessenger();
+ TestPlugin plugin1 = getPlugin();
+ TestPlugin plugin2 = getPlugin();
+ TestPlugin plugin3 = getPlugin();
+
+ messenger.registerOutgoingPluginChannel(plugin1, "foo");
+ messenger.registerOutgoingPluginChannel(plugin1, "bar");
+ messenger.registerOutgoingPluginChannel(plugin2, "baz");
+ messenger.registerOutgoingPluginChannel(plugin2, "qux");
+
+ assertEquals(messenger.getOutgoingChannels(plugin1), "foo", "bar");
+ assertEquals(messenger.getOutgoingChannels(plugin2), "baz", "qux");
+ assertEquals(messenger.getOutgoingChannels(plugin3));
+ }
+
+ @Test
+ public void testGetIncomingChannels() {
+ Messenger messenger = getMessenger();
+ TestPlugin plugin1 = getPlugin();
+ TestPlugin plugin2 = getPlugin();
+
+ assertEquals(messenger.getIncomingChannels());
+
+ messenger.registerIncomingPluginChannel(plugin1, "foo", new TestMessageListener("foo", "bar".getBytes()));
+ messenger.registerIncomingPluginChannel(plugin1, "bar", new TestMessageListener("foo", "bar".getBytes()));
+ messenger.registerIncomingPluginChannel(plugin2, "baz", new TestMessageListener("foo", "bar".getBytes()));
+ messenger.registerIncomingPluginChannel(plugin2, "baz", new TestMessageListener("foo", "bar".getBytes()));
+
+ assertEquals(messenger.getIncomingChannels(), "foo", "bar", "baz");
+ }
+
+ @Test
+ public void testGetIncomingChannels_Plugin() {
+ Messenger messenger = getMessenger();
+ TestPlugin plugin1 = getPlugin();
+ TestPlugin plugin2 = getPlugin();
+ TestPlugin plugin3 = getPlugin();
+
+ messenger.registerIncomingPluginChannel(plugin1, "foo", new TestMessageListener("foo", "bar".getBytes()));
+ messenger.registerIncomingPluginChannel(plugin1, "bar", new TestMessageListener("foo", "bar".getBytes()));
+ messenger.registerIncomingPluginChannel(plugin2, "baz", new TestMessageListener("foo", "bar".getBytes()));
+ messenger.registerIncomingPluginChannel(plugin2, "qux", new TestMessageListener("foo", "bar".getBytes()));
+
+ assertEquals(messenger.getIncomingChannels(plugin1), "foo", "bar");
+ assertEquals(messenger.getIncomingChannels(plugin2), "baz", "qux");
+ assertEquals(messenger.getIncomingChannels(plugin3));
+ }
+
+ @Test
+ public void testGetIncomingChannelRegistrations_Plugin() {
+ Messenger messenger = getMessenger();
+ TestPlugin plugin1 = getPlugin();
+ TestPlugin plugin2 = getPlugin();
+ TestPlugin plugin3 = getPlugin();
+ PluginMessageListenerRegistration registration1 = messenger.registerIncomingPluginChannel(plugin1, "foo", new TestMessageListener("foo", "bar".getBytes()));
+ PluginMessageListenerRegistration registration2 = messenger.registerIncomingPluginChannel(plugin1, "bar", new TestMessageListener("foo", "bar".getBytes()));
+ PluginMessageListenerRegistration registration3 = messenger.registerIncomingPluginChannel(plugin2, "baz", new TestMessageListener("foo", "bar".getBytes()));
+ PluginMessageListenerRegistration registration4 = messenger.registerIncomingPluginChannel(plugin2, "qux", new TestMessageListener("foo", "bar".getBytes()));
+
+ assertEquals(messenger.getIncomingChannelRegistrations(plugin1), registration1, registration2);
+ assertEquals(messenger.getIncomingChannelRegistrations(plugin2), registration3, registration4);
+ assertEquals(messenger.getIncomingChannels(plugin3));
+ }
+
+ @Test
+ public void testGetIncomingChannelRegistrations_String() {
+ Messenger messenger = getMessenger();
+ TestPlugin plugin1 = getPlugin();
+ TestPlugin plugin2 = getPlugin();
+ PluginMessageListenerRegistration registration1 = messenger.registerIncomingPluginChannel(plugin1, "foo", new TestMessageListener("foo", "bar".getBytes()));
+ PluginMessageListenerRegistration registration2 = messenger.registerIncomingPluginChannel(plugin1, "bar", new TestMessageListener("foo", "bar".getBytes()));
+ PluginMessageListenerRegistration registration3 = messenger.registerIncomingPluginChannel(plugin2, "foo", new TestMessageListener("foo", "bar".getBytes()));
+ PluginMessageListenerRegistration registration4 = messenger.registerIncomingPluginChannel(plugin2, "bar", new TestMessageListener("foo", "bar".getBytes()));
+
+ assertEquals(messenger.getIncomingChannelRegistrations("foo"), registration1, registration3);
+ assertEquals(messenger.getIncomingChannelRegistrations("bar"), registration2, registration4);
+ assertEquals(messenger.getIncomingChannelRegistrations("baz"));
+ }
+
+ @Test
+ public void testGetIncomingChannelRegistrations_Plugin_String() {
+ Messenger messenger = getMessenger();
+ TestPlugin plugin1 = getPlugin();
+ TestPlugin plugin2 = getPlugin();
+ TestPlugin plugin3 = getPlugin();
+ PluginMessageListenerRegistration registration1 = messenger.registerIncomingPluginChannel(plugin1, "foo", new TestMessageListener("foo", "bar".getBytes()));
+ PluginMessageListenerRegistration registration2 = messenger.registerIncomingPluginChannel(plugin1, "foo", new TestMessageListener("foo", "bar".getBytes()));
+ PluginMessageListenerRegistration registration3 = messenger.registerIncomingPluginChannel(plugin1, "bar", new TestMessageListener("foo", "bar".getBytes()));
+ PluginMessageListenerRegistration registration4 = messenger.registerIncomingPluginChannel(plugin2, "bar", new TestMessageListener("foo", "bar".getBytes()));
+ PluginMessageListenerRegistration registration5 = messenger.registerIncomingPluginChannel(plugin2, "baz", new TestMessageListener("foo", "bar".getBytes()));
+ PluginMessageListenerRegistration registration6 = messenger.registerIncomingPluginChannel(plugin2, "baz", new TestMessageListener("foo", "bar".getBytes()));
+
+ assertEquals(messenger.getIncomingChannelRegistrations(plugin1, "foo"), registration1, registration2);
+ assertEquals(messenger.getIncomingChannelRegistrations(plugin1, "bar"), registration3);
+ assertEquals(messenger.getIncomingChannelRegistrations(plugin2, "bar"), registration4);
+ assertEquals(messenger.getIncomingChannelRegistrations(plugin2, "baz"), registration5, registration6);
+ assertEquals(messenger.getIncomingChannelRegistrations(plugin1, "baz"));
+ assertEquals(messenger.getIncomingChannelRegistrations(plugin3, "qux"));
+ }
+
+ private static <T> void assertEquals(Collection<T> actual, T... expected) {
+ assertThat("Size of the array", actual.size(), is(expected.length));
+ assertThat(actual, hasItems(expected));
+ }
+}
diff --git a/src/test/java/org/bukkit/plugin/messaging/TestMessageListener.java b/src/test/java/org/bukkit/plugin/messaging/TestMessageListener.java
new file mode 100644
index 00000000..98860ec1
--- /dev/null
+++ b/src/test/java/org/bukkit/plugin/messaging/TestMessageListener.java
@@ -0,0 +1,29 @@
+package org.bukkit.plugin.messaging;
+
+import org.bukkit.entity.Player;
+import static org.junit.Assert.*;
+
+public class TestMessageListener implements PluginMessageListener {
+ private final String channel;
+ private final byte[] message;
+ private boolean received = false;
+
+ public TestMessageListener(String channel, byte[] message) {
+ this.channel = channel;
+ this.message = message;
+ }
+
+ public void onPluginMessageReceived(String channel, Player player, byte[] message) {
+ assertEquals(this.channel, channel);
+ assertArrayEquals(this.message, message);
+ this.received = true;
+ }
+
+ public boolean hasReceived() {
+ return received;
+ }
+
+ public void reset() {
+ received = false;
+ }
+}
diff --git a/src/test/java/org/bukkit/plugin/messaging/TestPlayer.java b/src/test/java/org/bukkit/plugin/messaging/TestPlayer.java
new file mode 100644
index 00000000..5c392a87
--- /dev/null
+++ b/src/test/java/org/bukkit/plugin/messaging/TestPlayer.java
@@ -0,0 +1,605 @@
+package org.bukkit.plugin.messaging;
+
+import java.net.InetSocketAddress;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+import org.bukkit.Achievement;
+import org.bukkit.Effect;
+import org.bukkit.GameMode;
+import org.bukkit.Instrument;
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.Note;
+import org.bukkit.Server;
+import org.bukkit.Statistic;
+import org.bukkit.World;
+import org.bukkit.block.Block;
+import org.bukkit.entity.Arrow;
+import org.bukkit.entity.Egg;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.Player;
+import org.bukkit.entity.Snowball;
+import org.bukkit.entity.Vehicle;
+import org.bukkit.event.entity.EntityDamageEvent;
+import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.PlayerInventory;
+import org.bukkit.map.MapView;
+import org.bukkit.permissions.Permission;
+import org.bukkit.permissions.PermissionAttachment;
+import org.bukkit.permissions.PermissionAttachmentInfo;
+import org.bukkit.plugin.Plugin;
+import org.bukkit.util.Vector;
+
+public class TestPlayer implements Player {
+ public String getDisplayName() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void setDisplayName(String name) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public String getPlayerListName() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void setPlayerListName(String name) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void setCompassTarget(Location loc) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public Location getCompassTarget() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public InetSocketAddress getAddress() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void sendRawMessage(String message) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void kickPlayer(String message) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void chat(String msg) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public boolean performCommand(String command) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public boolean isSneaking() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void setSneaking(boolean sneak) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public boolean isSprinting() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void setSprinting(boolean sprinting) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void saveData() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void loadData() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void setSleepingIgnored(boolean isSleeping) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public boolean isSleepingIgnored() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void playNote(Location loc, byte instrument, byte note) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void playNote(Location loc, Instrument instrument, Note note) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void playEffect(Location loc, Effect effect, int data) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void sendBlockChange(Location loc, Material material, byte data) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public boolean sendChunkChange(Location loc, int sx, int sy, int sz, byte[] data) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void sendBlockChange(Location loc, int material, byte data) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void sendMap(MapView map) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void updateInventory() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void awardAchievement(Achievement achievement) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void incrementStatistic(Statistic statistic) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void incrementStatistic(Statistic statistic, int amount) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void incrementStatistic(Statistic statistic, Material material) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void incrementStatistic(Statistic statistic, Material material, int amount) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void setPlayerTime(long time, boolean relative) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public long getPlayerTime() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public long getPlayerTimeOffset() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public boolean isPlayerTimeRelative() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void resetPlayerTime() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void giveExp(int amount) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public float getExp() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void setExp(float exp) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public int getExperience() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void setExperience(int exp) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public int getLevel() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void setLevel(int level) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public int getTotalExperience() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void setTotalExperience(int exp) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public float getExhaustion() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void setExhaustion(float value) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public float getSaturation() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void setSaturation(float value) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public int getFoodLevel() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void setFoodLevel(int value) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public Location getBedSpawnLocation() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public String getName() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public PlayerInventory getInventory() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public ItemStack getItemInHand() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void setItemInHand(ItemStack item) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public boolean isSleeping() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public int getSleepTicks() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public GameMode getGameMode() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void setGameMode(GameMode mode) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public int getHealth() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void setHealth(int health) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public int getMaxHealth() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public double getEyeHeight() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public double getEyeHeight(boolean ignoreSneaking) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public Location getEyeLocation() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public List<Block> getLineOfSight(HashSet<Byte> transparent, int maxDistance) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public Block getTargetBlock(HashSet<Byte> transparent, int maxDistance) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public List<Block> getLastTwoTargetBlocks(HashSet<Byte> transparent, int maxDistance) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public Egg throwEgg() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public Snowball throwSnowball() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public Arrow shootArrow() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public boolean isInsideVehicle() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public boolean leaveVehicle() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public Vehicle getVehicle() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public int getRemainingAir() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void setRemainingAir(int ticks) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public int getMaximumAir() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void setMaximumAir(int ticks) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void damage(int amount) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void damage(int amount, Entity source) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public int getMaximumNoDamageTicks() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void setMaximumNoDamageTicks(int ticks) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public int getLastDamage() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void setLastDamage(int damage) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public int getNoDamageTicks() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void setNoDamageTicks(int ticks) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public Player getKiller() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public Location getLocation() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void setVelocity(Vector velocity) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public Vector getVelocity() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public World getWorld() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public boolean teleport(Location location) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public boolean teleport(Location location, TeleportCause cause) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public boolean teleport(Entity destination) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public boolean teleport(Entity destination, TeleportCause cause) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public List<Entity> getNearbyEntities(double x, double y, double z) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public int getEntityId() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public int getFireTicks() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public int getMaxFireTicks() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void setFireTicks(int ticks) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public boolean isDead() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public Server getServer() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public Entity getPassenger() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public boolean setPassenger(Entity passenger) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public boolean isEmpty() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public boolean eject() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public float getFallDistance() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void setFallDistance(float distance) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void setLastDamageCause(EntityDamageEvent event) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public EntityDamageEvent getLastDamageCause() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public UUID getUniqueId() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public int getTicksLived() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void setTicksLived(int value) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public boolean isPermissionSet(String name) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public boolean isPermissionSet(Permission perm) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public boolean hasPermission(String name) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public boolean hasPermission(Permission perm) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public PermissionAttachment addAttachment(Plugin plugin) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value, int ticks) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public PermissionAttachment addAttachment(Plugin plugin, int ticks) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void removeAttachment(PermissionAttachment attachment) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void recalculatePermissions() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public Set<PermissionAttachmentInfo> getEffectivePermissions() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public boolean isOp() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void setOp(boolean value) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void sendMessage(String message) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public boolean isOnline() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public boolean isBanned() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void setBanned(boolean banned) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public boolean isWhitelisted() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void setWhitelisted(boolean value) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public Player getPlayer() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public long getFirstPlayed() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public long getLastPlayed() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public boolean hasPlayedBefore() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public Map<String, Object> serialize() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void sendPluginMessage(Plugin source, String channel, byte[] message) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public Set<String> getListeningPluginChannels() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+}
diff --git a/src/test/java/org/bukkit/plugin/messaging/TestPlugin.java b/src/test/java/org/bukkit/plugin/messaging/TestPlugin.java
new file mode 100644
index 00000000..060b742a
--- /dev/null
+++ b/src/test/java/org/bukkit/plugin/messaging/TestPlugin.java
@@ -0,0 +1,116 @@
+package org.bukkit.plugin.messaging;
+
+import com.avaje.ebean.EbeanServer;
+import java.io.File;
+import java.io.InputStream;
+import org.bukkit.Server;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandSender;
+import org.bukkit.configuration.file.FileConfiguration;
+import org.bukkit.event.Event.Type;
+import org.bukkit.generator.ChunkGenerator;
+import org.bukkit.plugin.Plugin;
+import org.bukkit.plugin.PluginDescriptionFile;
+import org.bukkit.plugin.PluginLoader;
+import org.bukkit.util.config.Configuration;
+
+public class TestPlugin implements Plugin {
+ private boolean enabled = true;
+
+ public void setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ }
+
+ public File getDataFolder() {
+ throw new UnsupportedOperationException("Not supported.");
+ }
+
+ public PluginDescriptionFile getDescription() {
+ throw new UnsupportedOperationException("Not supported.");
+ }
+
+ public Configuration getConfiguration() {
+ throw new UnsupportedOperationException("Not supported.");
+ }
+
+ public FileConfiguration getConfig() {
+ throw new UnsupportedOperationException("Not supported.");
+ }
+
+ public InputStream getResource(String filename) {
+ throw new UnsupportedOperationException("Not supported.");
+ }
+
+ public void saveConfig() {
+ throw new UnsupportedOperationException("Not supported.");
+ }
+
+ public void saveDefaultConfig() {
+ throw new UnsupportedOperationException("Not supported.");
+ }
+
+ public void saveResource(String resourcePath, boolean replace) {
+ throw new UnsupportedOperationException("Not supported.");
+ }
+
+ public void reloadConfig() {
+ throw new UnsupportedOperationException("Not supported.");
+ }
+
+ public PluginLoader getPluginLoader() {
+ throw new UnsupportedOperationException("Not supported.");
+ }
+
+ public Server getServer() {
+ throw new UnsupportedOperationException("Not supported.");
+ }
+
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ public void onDisable() {
+ throw new UnsupportedOperationException("Not supported.");
+ }
+
+ public void onLoad() {
+ throw new UnsupportedOperationException("Not supported.");
+ }
+
+ public void onEnable() {
+ throw new UnsupportedOperationException("Not supported.");
+ }
+
+ public boolean isNaggable() {
+ throw new UnsupportedOperationException("Not supported.");
+ }
+
+ public void setNaggable(boolean canNag) {
+ throw new UnsupportedOperationException("Not supported.");
+ }
+
+ public EbeanServer getDatabase() {
+ throw new UnsupportedOperationException("Not supported.");
+ }
+
+ public ChunkGenerator getDefaultWorldGenerator(String worldName, String id) {
+ throw new UnsupportedOperationException("Not supported.");
+ }
+
+ public long getTiming(Type type) {
+ throw new UnsupportedOperationException("Not supported.");
+ }
+
+ public void incTiming(Type type, long delta) {
+ throw new UnsupportedOperationException("Not supported.");
+ }
+
+ public void resetTimings() {
+ throw new UnsupportedOperationException("Not supported.");
+ }
+
+ public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
+ throw new UnsupportedOperationException("Not supported.");
+ }
+
+}