summaryrefslogtreecommitdiffstats
path: root/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'src/main')
-rw-r--r--src/main/java/org/bukkit/World.java3
-rw-r--r--src/main/java/org/bukkit/block/Block.java3
-rw-r--r--src/main/java/org/bukkit/block/BlockState.java3
-rw-r--r--src/main/java/org/bukkit/entity/Entity.java3
-rw-r--r--src/main/java/org/bukkit/metadata/FixedMetadataValue.java25
-rw-r--r--src/main/java/org/bukkit/metadata/LazyMetadataValue.java158
-rw-r--r--src/main/java/org/bukkit/metadata/MetadataConversionException.java13
-rw-r--r--src/main/java/org/bukkit/metadata/MetadataEvaluationException.java13
-rw-r--r--src/main/java/org/bukkit/metadata/MetadataStore.java52
-rw-r--r--src/main/java/org/bukkit/metadata/MetadataStoreBase.java143
-rw-r--r--src/main/java/org/bukkit/metadata/MetadataValue.java73
-rw-r--r--src/main/java/org/bukkit/metadata/Metadatable.java42
-rw-r--r--src/main/java/org/bukkit/plugin/Plugin.java71
-rw-r--r--src/main/java/org/bukkit/plugin/java/JavaPlugin.java2
-rw-r--r--src/main/java/org/bukkit/util/NumberConversions.java78
15 files changed, 614 insertions, 68 deletions
diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java
index 5212f961..1b326a55 100644
--- a/src/main/java/org/bukkit/World.java
+++ b/src/main/java/org/bukkit/World.java
@@ -13,13 +13,14 @@ import org.bukkit.block.Block;
import org.bukkit.entity.*;
import org.bukkit.generator.BlockPopulator;
import org.bukkit.inventory.ItemStack;
+import org.bukkit.metadata.Metadatable;
import org.bukkit.plugin.messaging.PluginMessageRecipient;
import org.bukkit.util.Vector;
/**
* Represents a world, which may contain entities, chunks and blocks
*/
-public interface World extends PluginMessageRecipient {
+public interface World extends PluginMessageRecipient, Metadatable {
/**
* Gets the {@link Block} at the given coordinates
diff --git a/src/main/java/org/bukkit/block/Block.java b/src/main/java/org/bukkit/block/Block.java
index 7ca3c01b..99bc5630 100644
--- a/src/main/java/org/bukkit/block/Block.java
+++ b/src/main/java/org/bukkit/block/Block.java
@@ -7,6 +7,7 @@ import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.Location;
import org.bukkit.inventory.ItemStack;
+import org.bukkit.metadata.Metadatable;
/**
* Represents a block. This is a live object, and only one Block may exist for
@@ -14,7 +15,7 @@ import org.bukkit.inventory.ItemStack;
* to your own handling of it; use block.getState() to get a snapshot state of a
* block which will not be modified.
*/
-public interface Block {
+public interface Block extends Metadatable {
/**
* Gets the metadata for this block
diff --git a/src/main/java/org/bukkit/block/BlockState.java b/src/main/java/org/bukkit/block/BlockState.java
index 7e181017..cd5bcfbf 100644
--- a/src/main/java/org/bukkit/block/BlockState.java
+++ b/src/main/java/org/bukkit/block/BlockState.java
@@ -5,6 +5,7 @@ import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.material.MaterialData;
+import org.bukkit.metadata.Metadatable;
/**
* Represents a captured state of a block, which will not change automatically.
@@ -14,7 +15,7 @@ import org.bukkit.material.MaterialData;
* the state of the block and you will not know, or they may change the block to
* another type entirely, causing your BlockState to become invalid.
*/
-public interface BlockState {
+public interface BlockState extends Metadatable {
/**
* Gets the block represented by this BlockState
diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java
index c8554734..d9d219b3 100644
--- a/src/main/java/org/bukkit/entity/Entity.java
+++ b/src/main/java/org/bukkit/entity/Entity.java
@@ -5,6 +5,7 @@ import org.bukkit.EntityEffect;
import org.bukkit.Server;
import org.bukkit.World;
import org.bukkit.event.entity.EntityDamageEvent;
+import org.bukkit.metadata.Metadatable;
import org.bukkit.util.Vector;
import java.util.List;
@@ -14,7 +15,7 @@ import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
/**
* Represents a base entity in the world
*/
-public interface Entity {
+public interface Entity extends Metadatable {
/**
* Gets the entity's current position
diff --git a/src/main/java/org/bukkit/metadata/FixedMetadataValue.java b/src/main/java/org/bukkit/metadata/FixedMetadataValue.java
new file mode 100644
index 00000000..41f89a0e
--- /dev/null
+++ b/src/main/java/org/bukkit/metadata/FixedMetadataValue.java
@@ -0,0 +1,25 @@
+package org.bukkit.metadata;
+
+import org.bukkit.plugin.Plugin;
+
+import java.util.concurrent.Callable;
+
+/**
+ * A FixedMetadataValue is a special case metadata item that contains the same value forever after initialization.
+ * Invalidating a FixedMetadataValue has no affect.
+ */
+public class FixedMetadataValue extends LazyMetadataValue {
+ /**
+ * Initializes a FixedMetadataValue with an Object
+ *
+ * @param owningPlugin the {@link Plugin} that created this metadata value.
+ * @param value the value assigned to this metadata value.
+ */
+ public FixedMetadataValue(Plugin owningPlugin, final Object value) {
+ super(owningPlugin, CacheStrategy.CACHE_ETERNALLY, new Callable<Object>() {
+ public Object call() throws Exception {
+ return value;
+ }
+ });
+ }
+}
diff --git a/src/main/java/org/bukkit/metadata/LazyMetadataValue.java b/src/main/java/org/bukkit/metadata/LazyMetadataValue.java
new file mode 100644
index 00000000..cc0ba506
--- /dev/null
+++ b/src/main/java/org/bukkit/metadata/LazyMetadataValue.java
@@ -0,0 +1,158 @@
+package org.bukkit.metadata;
+
+import java.lang.ref.SoftReference;
+import java.util.concurrent.Callable;
+
+import org.apache.commons.lang.Validate;
+import org.bukkit.plugin.Plugin;
+import org.bukkit.util.NumberConversions;
+
+/**
+ * The LazyMetadataValue class implements a type of metadata that is not computed until another plugin asks for it.
+ * By making metadata values lazy, no computation is done by the providing plugin until absolutely necessary (if ever).
+ * Additionally, LazyMetadataValue objects cache their values internally unless overridden by a {@link CacheStrategy}
+ * or invalidated at the individual or plugin level. Once invalidated, the LazyMetadataValue will recompute its value
+ * when asked.
+ */
+public class LazyMetadataValue implements MetadataValue {
+ private Callable<Object> lazyValue;
+ private CacheStrategy cacheStrategy;
+ private SoftReference<Object> internalValue = new SoftReference<Object>(null);
+ private Plugin owningPlugin;
+ private static final Object ACTUALLY_NULL = new Object();
+
+ /**
+ * Initialized a LazyMetadataValue object with the default CACHE_AFTER_FIRST_EVAL cache strategy.
+ *
+ * @param owningPlugin the {@link Plugin} that created this metadata value.
+ * @param lazyValue the lazy value assigned to this metadata value.
+ */
+ public LazyMetadataValue(Plugin owningPlugin, Callable<Object> lazyValue) {
+ this(owningPlugin, CacheStrategy.CACHE_AFTER_FIRST_EVAL, lazyValue);
+ }
+
+ /**
+ * Initializes a LazyMetadataValue object with a specific cache strategy.
+ *
+ * @param owningPlugin the {@link Plugin} that created this metadata value.
+ * @param cacheStrategy determines the rules for caching this metadata value.
+ * @param lazyValue the lazy value assigned to this metadata value.
+ */
+ public LazyMetadataValue(Plugin owningPlugin, CacheStrategy cacheStrategy, Callable<Object> lazyValue) {
+ Validate.notNull(owningPlugin, "owningPlugin cannot be null");
+ Validate.notNull(cacheStrategy, "cacheStrategy cannot be null");
+ Validate.notNull(lazyValue, "lazyValue cannot be null");
+
+ this.lazyValue = lazyValue;
+ this.owningPlugin = owningPlugin;
+ this.cacheStrategy = cacheStrategy;
+ }
+
+ public Plugin getOwningPlugin() {
+ return owningPlugin;
+ }
+
+ public Object value() {
+ eval();
+ Object value = internalValue.get();
+ if (value == ACTUALLY_NULL) {
+ return null;
+ }
+ return value;
+ }
+
+ public int asInt() {
+ return NumberConversions.toInt(value());
+ }
+
+ public float asFloat() {
+ return NumberConversions.toFloat(value());
+ }
+
+ public double asDouble() {
+ return NumberConversions.toDouble(value());
+ }
+
+ public long asLong() {
+ return NumberConversions.toLong(value());
+ }
+
+ public short asShort() {
+ return NumberConversions.toShort(value());
+ }
+
+ public byte asByte() {
+ return NumberConversions.toByte(value());
+ }
+
+ public boolean asBoolean() {
+ Object value = value();
+ if (value instanceof Boolean) {
+ return (Boolean) value;
+ }
+
+ if (value instanceof Number) {
+ return ((Number) value).intValue() != 0;
+ }
+
+ if (value instanceof String) {
+ return Boolean.parseBoolean((String) value);
+ }
+
+ return value != null;
+ }
+
+ public String asString() {
+ Object value = value();
+
+ if (value == null) {
+ return "";
+ }
+ return value.toString();
+ }
+
+ /**
+ * Lazily evaluates the value of this metadata item.
+ *
+ * @throws MetadataEvaluationException if computing the metadata value fails.
+ */
+ private synchronized void eval() throws MetadataEvaluationException {
+ if (cacheStrategy == CacheStrategy.NEVER_CACHE || internalValue.get() == null) {
+ try {
+ Object value = lazyValue.call();
+ if (value == null) {
+ value = ACTUALLY_NULL;
+ }
+ internalValue = new SoftReference<Object>(value);
+ } catch (Exception e) {
+ throw new MetadataEvaluationException(e);
+ }
+ }
+ }
+
+ public synchronized void invalidate() {
+ if (cacheStrategy != CacheStrategy.CACHE_ETERNALLY) {
+ internalValue.clear();
+ }
+ }
+
+ /**
+ * Describes possible caching strategies for metadata.
+ */
+ public enum CacheStrategy {
+ /**
+ * Once the metadata value has been evaluated, do not re-evaluate the value until it is manually invalidated.
+ */
+ CACHE_AFTER_FIRST_EVAL,
+
+ /**
+ * Re-evaluate the metadata item every time it is requested
+ */
+ NEVER_CACHE,
+
+ /**
+ * Once the metadata value has been evaluated, do not re-evaluate the value in spite of manual invalidation.
+ */
+ CACHE_ETERNALLY
+ }
+}
diff --git a/src/main/java/org/bukkit/metadata/MetadataConversionException.java b/src/main/java/org/bukkit/metadata/MetadataConversionException.java
new file mode 100644
index 00000000..ff4d1205
--- /dev/null
+++ b/src/main/java/org/bukkit/metadata/MetadataConversionException.java
@@ -0,0 +1,13 @@
+package org.bukkit.metadata;
+
+/**
+ * A MetadataConversionException is thrown any time a {@link LazyMetadataValue} attempts to convert a metadata value
+ * to an inappropriate data type.
+ */
+
+@SuppressWarnings("serial")
+public class MetadataConversionException extends RuntimeException {
+ MetadataConversionException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/org/bukkit/metadata/MetadataEvaluationException.java b/src/main/java/org/bukkit/metadata/MetadataEvaluationException.java
new file mode 100644
index 00000000..6b5ac886
--- /dev/null
+++ b/src/main/java/org/bukkit/metadata/MetadataEvaluationException.java
@@ -0,0 +1,13 @@
+package org.bukkit.metadata;
+
+/**
+ * A MetadataEvaluationException is thrown any time a {@link LazyMetadataValue} fails to evaluate its value due to
+ * an exception. The originating exception will be included as this exception's cause.
+ */
+
+@SuppressWarnings("serial")
+public class MetadataEvaluationException extends RuntimeException {
+ MetadataEvaluationException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/src/main/java/org/bukkit/metadata/MetadataStore.java b/src/main/java/org/bukkit/metadata/MetadataStore.java
new file mode 100644
index 00000000..0adfa7a0
--- /dev/null
+++ b/src/main/java/org/bukkit/metadata/MetadataStore.java
@@ -0,0 +1,52 @@
+package org.bukkit.metadata;
+
+import org.bukkit.plugin.Plugin;
+
+import java.util.List;
+
+public interface MetadataStore<T> {
+ /**
+ * Adds a metadata value to an object.
+ *
+ * @param subject The object receiving the metadata.
+ * @param metadataKey A unique key to identify this metadata.
+ * @param newMetadataValue The metadata value to apply.
+ */
+ public void setMetadata(T subject, String metadataKey, MetadataValue newMetadataValue);
+
+ /**
+ * Returns all metadata values attached to an object. If multiple plugins have attached metadata, each will value
+ * will be included.
+ *
+ * @param subject the object being interrogated.
+ * @param metadataKey the unique metadata key being sought.
+ * @return A list of values, one for each plugin that has set the requested value.
+ */
+ public List<MetadataValue> getMetadata(T subject, String metadataKey);
+
+ /**
+ * Tests to see if a metadata attribute has been set on an object.
+ *
+ * @param subject the object upon which the has-metadata test is performed.
+ * @param metadataKey the unique metadata key being queried.
+ * @return the existence of the metadataKey within subject.
+ */
+ public boolean hasMetadata(T subject, String metadataKey);
+
+ /**
+ * Removes a metadata item owned by a plugin from a subject.
+ *
+ * @param subject the object to remove the metadata from.
+ * @param metadataKey the unique metadata key identifying the metadata to remove.
+ * @param owningPlugin the plugin attempting to remove a metadata item.
+ */
+ public void removeMetadata(T subject, String metadataKey, Plugin owningPlugin);
+
+ /**
+ * Invalidates all metadata in the metadata store that originates from the given plugin. Doing this will force
+ * each invalidated metadata item to be recalculated the next time it is accessed.
+ *
+ * @param owningPlugin the plugin requesting the invalidation.
+ */
+ public void invalidateAll(Plugin owningPlugin);
+}
diff --git a/src/main/java/org/bukkit/metadata/MetadataStoreBase.java b/src/main/java/org/bukkit/metadata/MetadataStoreBase.java
new file mode 100644
index 00000000..0c384abe
--- /dev/null
+++ b/src/main/java/org/bukkit/metadata/MetadataStoreBase.java
@@ -0,0 +1,143 @@
+package org.bukkit.metadata;
+
+import org.bukkit.plugin.Plugin;
+
+import java.util.*;
+
+public abstract class MetadataStoreBase<T> {
+ private Map<String, List<MetadataValue>> metadataMap = new HashMap<String, List<MetadataValue>>();
+ private WeakHashMap<T, String> disambiguationCache = new WeakHashMap<T, String>();
+
+ /**
+ * Adds a metadata value to an object. Each metadata value is owned by a specific{@link Plugin}.
+ * If a plugin has already added a metadata value to an object, that value
+ * will be replaced with the value of {@code newMetadataValue}. Multiple plugins can set independent values for
+ * the same {@code metadataKey} without conflict.
+ *
+ * Implementation note: I considered using a {@link java.util.concurrent.locks.ReadWriteLock} for controlling
+ * access to {@code metadataMap}, but decided that the added overhead wasn't worth the finer grained access control.
+ * Bukkit is almost entirely single threaded so locking overhead shouldn't pose a problem.
+ *
+ * @see MetadataStore#setMetadata(Object, String, MetadataValue)
+ * @param subject The object receiving the metadata.
+ * @param metadataKey A unique key to identify this metadata.
+ * @param newMetadataValue The metadata value to apply.
+ */
+ public synchronized void setMetadata(T subject, String metadataKey, MetadataValue newMetadataValue) {
+ String key = cachedDisambiguate(subject, metadataKey);
+ if (!metadataMap.containsKey(key)) {
+ metadataMap.put(key, new ArrayList<MetadataValue>());
+ }
+ // we now have a list of subject's metadata for the given metadata key. If newMetadataValue's owningPlugin
+ // is found in this list, replace the value rather than add a new one.
+ List<MetadataValue> metadataList = metadataMap.get(key);
+ for (int i = 0; i < metadataList.size(); i++) {
+ if (metadataList.get(i).getOwningPlugin().equals(newMetadataValue.getOwningPlugin())) {
+ metadataList.set(i, newMetadataValue);
+ return;
+ }
+ }
+ // we didn't find a duplicate...add the new metadata value
+ metadataList.add(newMetadataValue);
+ }
+
+ /**
+ * Returns all metadata values attached to an object. If multiple plugins have attached metadata, each will value
+ * will be included.
+ *
+ * @see MetadataStore#getMetadata(Object, String)
+ * @param subject the object being interrogated.
+ * @param metadataKey the unique metadata key being sought.
+ * @return A list of values, one for each plugin that has set the requested value.
+ */
+ public synchronized List<MetadataValue> getMetadata(T subject, String metadataKey) {
+ String key = cachedDisambiguate(subject, metadataKey);
+ if (metadataMap.containsKey(key)) {
+ return Collections.unmodifiableList(metadataMap.get(key));
+ } else {
+ return Collections.emptyList();
+ }
+ }
+
+ /**
+ * Tests to see if a metadata attribute has been set on an object.
+ *
+ * @param subject the object upon which the has-metadata test is performed.
+ * @param metadataKey the unique metadata key being queried.
+ * @return the existence of the metadataKey within subject.
+ */
+ public synchronized boolean hasMetadata(T subject, String metadataKey) {
+ String key = cachedDisambiguate(subject, metadataKey);
+ return metadataMap.containsKey(key);
+ }
+
+ /**
+ * Removes a metadata item owned by a plugin from a subject.
+ *
+ * @see MetadataStore#removeMetadata(Object, String, org.bukkit.plugin.Plugin)
+ * @param subject the object to remove the metadata from.
+ * @param metadataKey the unique metadata key identifying the metadata to remove.
+ * @param owningPlugin the plugin attempting to remove a metadata item.
+ */
+ public synchronized void removeMetadata(T subject, String metadataKey, Plugin owningPlugin) {
+ String key = cachedDisambiguate(subject, metadataKey);
+ List<MetadataValue> metadataList = metadataMap.get(key);
+ for (int i = 0; i < metadataList.size(); i++) {
+ if (metadataList.get(i).getOwningPlugin().equals(owningPlugin)) {
+ metadataList.remove(i);
+ }
+ }
+ }
+
+ /**
+ * Invalidates all metadata in the metadata store that originates from the given plugin. Doing this will force
+ * each invalidated metadata item to be recalculated the next time it is accessed.
+ *
+ * @see MetadataStore#invalidateAll(org.bukkit.plugin.Plugin)
+ * @param owningPlugin the plugin requesting the invalidation.
+ */
+ public synchronized void invalidateAll(Plugin owningPlugin) {
+ if(owningPlugin == null) {
+ throw new IllegalArgumentException("owningPlugin cannot be null");
+ }
+
+ for (List<MetadataValue> values : metadataMap.values()) {
+ for (MetadataValue value : values) {
+ if (value.getOwningPlugin().equals(owningPlugin)) {
+ value.invalidate();
+ }
+ }
+ }
+ }
+
+ /**
+ * Caches the results of calls to {@link MetadataStoreBase#disambiguate(Object, String)} in a {@link WeakHashMap}. Doing so maintains a
+ * <a href="http://www.codeinstructions.com/2008/09/weakhashmap-is-not-cache-understanding.html">canonical list</a>
+ * of disambiguation strings for objects in memory. When those objects are garbage collected, the disambiguation string
+ * in the list is aggressively garbage collected as well.
+ * @param subject The object for which this key is being generated.
+ * @param metadataKey The name identifying the metadata value.
+ * @return a unique metadata key for the given subject.
+ */
+ private String cachedDisambiguate(T subject, String metadataKey) {
+ if (disambiguationCache.containsKey(subject)) {
+ return disambiguationCache.get(subject);
+ } else {
+ String disambiguation = disambiguate(subject, metadataKey);
+ disambiguationCache.put(subject, disambiguation);
+ return disambiguation;
+ }
+ }
+
+ /**
+ * Creates a unique name for the object receiving metadata by combining unique data from the subject with a metadataKey.
+ * The name created must be globally unique for the given object and any two equivalent objects must generate the
+ * same unique name. For example, two Player objects must generate the same string if they represent the same player,
+ * even if the objects would fail a reference equality test.
+ *
+ * @param subject The object for which this key is being generated.
+ * @param metadataKey The name identifying the metadata value.
+ * @return a unique metadata key for the given subject.
+ */
+ protected abstract String disambiguate(T subject, String metadataKey);
+}
diff --git a/src/main/java/org/bukkit/metadata/MetadataValue.java b/src/main/java/org/bukkit/metadata/MetadataValue.java
new file mode 100644
index 00000000..761d1ac9
--- /dev/null
+++ b/src/main/java/org/bukkit/metadata/MetadataValue.java
@@ -0,0 +1,73 @@
+package org.bukkit.metadata;
+
+import org.bukkit.plugin.Plugin;
+
+public interface MetadataValue {
+
+ /**
+ * Fetches the value of this metadata item.
+ *
+ * @return the metadata value.
+ */
+ public Object value();
+
+ /**
+ * Attempts to convert the value of this metadata item into an int.
+ * @return the value as an int.
+ */
+ public int asInt();
+
+ /**
+ * Attempts to convert the value of this metadata item into a float.
+ * @return the value as a float.
+ */
+ public float asFloat();
+
+ /**
+ * Attempts to convert the value of this metadata item into a double.
+ * @return the value as a double.
+ */
+ public double asDouble();
+
+ /**
+ * Attempts to convert the value of this metadata item into a long.
+ * @return the value as a long.
+ */
+ public long asLong();
+
+ /**
+ * Attempts to convert the value of this metadata item into a short.
+ * @return the value as a short.
+ */
+ public short asShort();
+
+ /**
+ * Attempts to convert the value of this metadata item into a byte.
+ * @return the value as a byte.
+ */
+ public byte asByte();
+
+ /**
+ * Attempts to convert the value of this metadata item into a boolean.
+ * @return the value as a boolean.
+ */
+ public boolean asBoolean();
+
+ /**
+ * Attempts to convert the value of this metadata item into a string.
+ * @return the value as a string.
+ */
+ public String asString();
+
+ /**
+ * Returns the {@link Plugin} that created this metadata item.
+ *
+ * @return the plugin that owns this metadata value.
+ */
+ public Plugin getOwningPlugin();
+
+ /**
+ * Invalidates this metadata item, forcing it to recompute when next accessed.
+ */
+ public void invalidate();
+}
diff --git a/src/main/java/org/bukkit/metadata/Metadatable.java b/src/main/java/org/bukkit/metadata/Metadatable.java
new file mode 100644
index 00000000..956a1960
--- /dev/null
+++ b/src/main/java/org/bukkit/metadata/Metadatable.java
@@ -0,0 +1,42 @@
+package org.bukkit.metadata;
+
+import org.bukkit.plugin.Plugin;
+
+import java.util.List;
+
+/**
+ * This interface is implemented by all objects that can provide metadata about themselves.
+ */
+public interface Metadatable {
+ /**
+ * Sets a metadata value in the implementing object's metadata store.
+ *
+ * @param metadataKey A unique key to identify this metadata.
+ * @param newMetadataValue The metadata value to apply.
+ */
+ public void setMetadata(String metadataKey, MetadataValue newMetadataValue);
+
+ /**
+ * Returns a list of previously set metadata values from the implementing object's metadata store.
+ *
+ * @param metadataKey the unique metadata key being sought.
+ * @return A list of values, one for each plugin that has set the requested value.
+ */
+ public List<MetadataValue> getMetadata(String metadataKey);
+
+ /**
+ * Tests to see whether the implementing object contains the given metadata value in its metadata store.
+ *
+ * @param metadataKey the unique metadata key being queried.
+ * @return the existence of the metadataKey within subject.
+ */
+ public boolean hasMetadata(String metadataKey);
+
+ /**
+ * Removes the given metadata value from the implementing object's metadata store.
+ *
+ * @param metadataKey the unique metadata key identifying the metadata to remove.
+ * @param owningPlugin This plugin's metadata value will be removed. All other values will be left untouched.
+ */
+ public void removeMetadata(String metadataKey, Plugin owningPlugin);
+}
diff --git a/src/main/java/org/bukkit/plugin/Plugin.java b/src/main/java/org/bukkit/plugin/Plugin.java
index 450252d8..97c882aa 100644
--- a/src/main/java/org/bukkit/plugin/Plugin.java
+++ b/src/main/java/org/bukkit/plugin/Plugin.java
@@ -14,22 +14,21 @@ import com.avaje.ebean.EbeanServer;
/**
* Represents a Plugin
*/
-public interface Plugin extends CommandExecutor {
-
+public abstract class Plugin implements CommandExecutor {
/**
* Returns the folder that the plugin data's files are located in. The
* folder may not yet exist.
*
* @return The folder
*/
- public File getDataFolder();
+ public abstract File getDataFolder();
/**
* Returns the plugin.yaml file containing the details for this plugin
*
* @return Contents of the plugin.yaml file
*/
- public PluginDescriptionFile getDescription();
+ public abstract PluginDescriptionFile getDescription();
/**
* Gets a {@link FileConfiguration} for this plugin, read through "config.yml"
@@ -39,7 +38,7 @@ public interface Plugin extends CommandExecutor {
*
* @return Plugin configuration
*/
- public FileConfiguration getConfig();
+ public abstract FileConfiguration getConfig();
/**
* Gets an embedded resource in this plugin
@@ -47,18 +46,18 @@ public interface Plugin extends CommandExecutor {
* @param filename Filename of the resource
* @return File if found, otherwise null
*/
- public InputStream getResource(String filename);
+ public abstract InputStream getResource(String filename);
/**
* Saves the {@link FileConfiguration} retrievable by {@link #getConfig()}.
*/
- public void saveConfig();
+ public abstract void saveConfig();
/**
* Saves the raw contents of the default config.yml file to the location retrievable by {@link #getConfig()}.
* If there is no default config.yml embedded in the plugin, an empty config.yml file is saved.
*/
- public void saveDefaultConfig();
+ public abstract void saveDefaultConfig();
/**
* Saves the raw contents of any resource embedded with a plugin's .jar file assuming it can be found using
@@ -69,70 +68,70 @@ public interface Plugin extends CommandExecutor {
* @param replace if true, the embedded resource will overwrite the contents of an existing file.
* @throws IllegalArgumentException if the resource path is null, empty, or points to a nonexistent resource.
*/
- public void saveResource(String resourcePath, boolean replace);
+ public abstract void saveResource(String resourcePath, boolean replace);
/**
* Discards any data in {@link #getConfig()} and reloads from disk.
*/
- public void reloadConfig();
+ public abstract void reloadConfig();
/**
* Gets the associated PluginLoader responsible for this plugin
*
* @return PluginLoader that controls this plugin
*/
- public PluginLoader getPluginLoader();
+ public abstract PluginLoader getPluginLoader();
/**
* Returns the Server instance currently running this plugin
*
* @return Server running this plugin
*/
- public Server getServer();
+ public abstract Server getServer();
/**
* Returns a value indicating whether or not this plugin is currently enabled
*
* @return true if this plugin is enabled, otherwise false
*/
- public boolean isEnabled();
+ public abstract boolean isEnabled();
/**
* Called when this plugin is disabled
*/
- public void onDisable();
+ public abstract void onDisable();
/**
* Called after a plugin is loaded but before it has been enabled.
* When mulitple plugins are loaded, the onLoad() for all plugins is called before any onEnable() is called.
*/
- public void onLoad();
+ public abstract void onLoad();
/**
* Called when this plugin is enabled
*/
- public void onEnable();
+ public abstract void onEnable();
/**
* Simple boolean if we can still nag to the logs about things
*
* @return boolean whether we can nag
*/
- public boolean isNaggable();
+ public abstract boolean isNaggable();
/**
* Set naggable state
*
* @param canNag is this plugin still naggable?
*/
- public void setNaggable(boolean canNag);
+ public abstract void setNaggable(boolean canNag);
/**
* Gets the {@link EbeanServer} tied to this plugin
*
* @return Ebean server instance
*/
- public EbeanServer getDatabase();
+ public abstract EbeanServer getDatabase();
/**
* Gets a {@link ChunkGenerator} for use in a default world, as specified in the server configuration
@@ -141,7 +140,7 @@ public interface Plugin extends CommandExecutor {
* @param id Unique ID, if any, that was specified to indicate which generator was requested
* @return ChunkGenerator for use in the default world generation
*/
- public ChunkGenerator getDefaultWorldGenerator(String worldName, String id);
+ public abstract ChunkGenerator getDefaultWorldGenerator(String worldName, String id);
/**
* Returns the primary logger associated with this server instance. The returned logger automatically
@@ -149,5 +148,35 @@ public interface Plugin extends CommandExecutor {
*
* @return Logger associated with this server
*/
- public Logger getLogger();
+ public abstract Logger getLogger();
+
+ /**
+ * Returns the name of the plugin.
+ *
+ * This should return the bare name of the plugin and should be used for comparison.
+ *
+ * @return name of the plugin
+ */
+ public String getName() {
+ return getDescription().getName();
+ }
+
+ @Override
+ public int hashCode() {
+ return getName().hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (!(obj instanceof Plugin)) {
+ return false;
+ }
+ return getName().equals(((Plugin) obj).getName());
+ }
}
diff --git a/src/main/java/org/bukkit/plugin/java/JavaPlugin.java b/src/main/java/org/bukkit/plugin/java/JavaPlugin.java
index 10b19e91..6cc7d9db 100644
--- a/src/main/java/org/bukkit/plugin/java/JavaPlugin.java
+++ b/src/main/java/org/bukkit/plugin/java/JavaPlugin.java
@@ -34,7 +34,7 @@ import com.avaje.ebeaninternal.server.ddl.DdlGenerator;
/**
* Represents a Java plugin
*/
-public abstract class JavaPlugin implements Plugin {
+public abstract class JavaPlugin extends Plugin {
private boolean isEnabled = false;
private boolean initialized = false;
private PluginLoader loader = null;
diff --git a/src/main/java/org/bukkit/util/NumberConversions.java b/src/main/java/org/bukkit/util/NumberConversions.java
index f70cc314..9c0b132f 100644
--- a/src/main/java/org/bukkit/util/NumberConversions.java
+++ b/src/main/java/org/bukkit/util/NumberConversions.java
@@ -9,84 +9,78 @@ public final class NumberConversions {
public static int toInt(Object object) {
if (object instanceof Number) {
return ((Number) object).intValue();
- } else {
- int result = 0;
-
- try {
- result = Integer.parseInt(object.toString());
- } catch (NumberFormatException ex) {}
+ }
- return result;
+ try {
+ return Integer.valueOf(object.toString());
+ } catch (NumberFormatException e) {
+ } catch (NullPointerException e) {
}
+ return 0;
}
public static float toFloat(Object object) {
if (object instanceof Number) {
return ((Number) object).floatValue();
- } else {
- float result = 0;
-
- try {
- result = Float.parseFloat(object.toString());
- } catch (NumberFormatException ex) {}
+ }
- return result;
+ try {
+ return Float.valueOf(object.toString());
+ } catch (NumberFormatException e) {
+ } catch (NullPointerException e) {
}
+ return 0;
}
public static double toDouble(Object object) {
if (object instanceof Number) {
return ((Number) object).doubleValue();
- } else {
- double result = 0;
-
- try {
- result = Double.parseDouble(object.toString());
- } catch (NumberFormatException ex) {}
+ }
- return result;
+ try {
+ return Double.valueOf(object.toString());
+ } catch (NumberFormatException e) {
+ } catch (NullPointerException e) {
}
+ return 0;
}
public static long toLong(Object object) {
if (object instanceof Number) {
return ((Number) object).longValue();
- } else {
- long result = 0;
-
- try {
- result = Long.parseLong(object.toString());
- } catch (NumberFormatException ex) {}
+ }
- return result;
+ try {
+ return Long.valueOf(object.toString());
+ } catch (NumberFormatException e) {
+ } catch (NullPointerException e) {
}
+ return 0;
}
public static short toShort(Object object) {
if (object instanceof Number) {
return ((Number) object).shortValue();
- } else {
- short result = 0;
-
- try {
- result = Short.parseShort(object.toString());
- } catch (NumberFormatException ex) {}
+ }
- return result;
+ try {
+ return Short.valueOf(object.toString());
+ } catch (NumberFormatException e) {
+ } catch (NullPointerException e) {
}
+ return 0;
}
public static byte toByte(Object object) {
if (object instanceof Number) {
return ((Number) object).byteValue();
- } else {
- byte result = 0;
-
- try {
- result = Byte.parseByte(object.toString());
- } catch (NumberFormatException ex) {}
+ }
- return result;
+ try {
+ return Byte.valueOf(object.toString());
+ } catch (NumberFormatException e) {
+ } catch (NullPointerException e) {
}
+ return 0;
}
}