mirror of
https://github.com/BentoBoxWorld/BentoBox.git
synced 2024-11-23 03:05:16 +01:00
Adds a persistent metadata API to User and Island classes.
This is modeled after the Bukkit metadata API with the difference that it is persistent, i.e., metadata is stored to the database. Metadata can be placed on Islands or Users. This API should be useful for addons that do not want or need to create their own database tables and instead just want to tag the user with some data, or tag the island with some data. It is intended for small amounts of data, like boolean tags or other values.
This commit is contained in:
parent
e84b1f1830
commit
d7c7559546
@ -0,0 +1,48 @@
|
||||
package world.bentobox.bentobox.api.metadata;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNull;
|
||||
|
||||
/**
|
||||
* This interface is for all BentoBox objects that have meta data
|
||||
* @author tastybento
|
||||
* @since 1.15.4
|
||||
*/
|
||||
public interface MetaDataAble {
|
||||
/**
|
||||
* @return the metaData
|
||||
*/
|
||||
public Map<String, MetaDataValue> getMetaData();
|
||||
|
||||
/**
|
||||
* Get meta data by key
|
||||
* @param key - key
|
||||
* @return the value to which the specified key is mapped, or null if there is no mapping for the key
|
||||
* @since 1.15.4
|
||||
*/
|
||||
public MetaDataValue getMetaData(@NonNull String key);
|
||||
|
||||
/**
|
||||
* @param metaData the metaData to set
|
||||
* @since 1.15.4
|
||||
*/
|
||||
public void setMetaData(Map<String, MetaDataValue> metaData);
|
||||
|
||||
/**
|
||||
* Put a key, value string pair into the object's meta data
|
||||
* @param key - key
|
||||
* @param value - value
|
||||
* @return the previous value associated with key, or null if there was no mapping for key.
|
||||
* @since 1.15.4
|
||||
*/
|
||||
public MetaDataValue putMetaData(@NonNull String key, @NonNull MetaDataValue value);
|
||||
|
||||
/**
|
||||
* Remove meta data
|
||||
* @param key - key to remove
|
||||
* @return the previous value associated with key, or null if there was no mapping for key.
|
||||
* @since 1.15.4
|
||||
*/
|
||||
public MetaDataValue removeMetaData(@NonNull String key);
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
package world.bentobox.bentobox.api.metadata;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNull;
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
|
||||
/**
|
||||
* Stores meta data value in a GSON friendly way so it can be serialized and deserialized.
|
||||
* Values that are null are not stored in the database, so only the appropriate type is stored.
|
||||
* @author tastybento
|
||||
* @since 1.15.4
|
||||
*
|
||||
*/
|
||||
public class MetaDataValue {
|
||||
|
||||
// Use classes so null value is supported
|
||||
@Expose
|
||||
private Integer intValue;
|
||||
@Expose
|
||||
private Float floatValue;
|
||||
@Expose
|
||||
private Double doubleValue;
|
||||
@Expose
|
||||
private Long longValue;
|
||||
@Expose
|
||||
private Short shortValue;
|
||||
@Expose
|
||||
private Byte byteValue;
|
||||
@Expose
|
||||
private Boolean booleanValue;
|
||||
@Expose
|
||||
private @NonNull String stringValue;
|
||||
|
||||
/**
|
||||
* Initialize this meta data value
|
||||
* @param value the value assigned to this metadata value
|
||||
*/
|
||||
public MetaDataValue(@NonNull Object value) {
|
||||
if (value instanceof Integer) {
|
||||
intValue = (int)value;
|
||||
} else if (value instanceof Float) {
|
||||
floatValue = (float)value;
|
||||
} else if (value instanceof Double) {
|
||||
doubleValue = (double)value;
|
||||
} else if (value instanceof Long) {
|
||||
longValue = (long)value;
|
||||
} else if (value instanceof Short) {
|
||||
shortValue = (short)value;
|
||||
} else if (value instanceof Byte) {
|
||||
byteValue = (byte)value;
|
||||
} else if (value instanceof Boolean) {
|
||||
booleanValue = (boolean)value;
|
||||
} else if (value instanceof String) {
|
||||
stringValue = (String)value;
|
||||
}
|
||||
}
|
||||
|
||||
public int asInt() {
|
||||
return intValue;
|
||||
}
|
||||
|
||||
public float asFloat() {
|
||||
return floatValue;
|
||||
}
|
||||
|
||||
public double asDouble() {
|
||||
return doubleValue;
|
||||
}
|
||||
|
||||
public long asLong() {
|
||||
return longValue;
|
||||
}
|
||||
|
||||
public short asShort() {
|
||||
return shortValue;
|
||||
}
|
||||
|
||||
public byte asByte() {
|
||||
return byteValue;
|
||||
}
|
||||
|
||||
public boolean asBoolean() {
|
||||
return booleanValue;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public String asString() {
|
||||
return stringValue;
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
@ -29,6 +30,7 @@ import org.eclipse.jdt.annotation.Nullable;
|
||||
import world.bentobox.bentobox.BentoBox;
|
||||
import world.bentobox.bentobox.api.addons.Addon;
|
||||
import world.bentobox.bentobox.api.events.OfflineMessageEvent;
|
||||
import world.bentobox.bentobox.api.metadata.MetaDataValue;
|
||||
import world.bentobox.bentobox.util.Util;
|
||||
|
||||
/**
|
||||
@ -631,4 +633,53 @@ public class User {
|
||||
public void setAddon(Addon addon) {
|
||||
this.addon = addon;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the meta data for this user
|
||||
* @return the metaData
|
||||
* @since 1.15.4
|
||||
*/
|
||||
@NonNull
|
||||
public Map<String, MetaDataValue> getMetaData() {
|
||||
return plugin.getPlayers().getPlayer(playerUUID).getMetaData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get meta data by key
|
||||
* @param key - key
|
||||
* @return optional value to which the specified key is mapped, or empty if there is no mapping for the key
|
||||
* @since 1.15.4
|
||||
*/
|
||||
public Optional<MetaDataValue> getMetaData(String key) {
|
||||
return Optional.ofNullable(plugin.getPlayers().getPlayer(playerUUID).getMetaData().get(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param metaData the metaData to set
|
||||
* @since 1.15.4
|
||||
*/
|
||||
public void setMetaData(Map<String, MetaDataValue> metaData) {
|
||||
plugin.getPlayers().getPlayer(playerUUID).setMetaData(metaData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Put a key, value string pair into the user's meta data
|
||||
* @param key - key
|
||||
* @param value - value
|
||||
* @return the previous value associated with key, or empty if there was no mapping for key.
|
||||
* @since 1.15.4
|
||||
*/
|
||||
public Optional<MetaDataValue> putMetaData(String key, MetaDataValue value) {
|
||||
return Optional.ofNullable(plugin.getPlayers().getPlayer(playerUUID).getMetaData().put(key, value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove meta data
|
||||
* @param key - key to remove
|
||||
* @return the previous value associated with key, or empty if there was no mapping for key.
|
||||
* @since 1.15.4
|
||||
*/
|
||||
public Optional<MetaDataValue> removeMetaData(String key) {
|
||||
return Optional.ofNullable(plugin.getPlayers().getPlayer(playerUUID).getMetaData().remove(key));
|
||||
}
|
||||
}
|
||||
|
@ -34,6 +34,8 @@ import world.bentobox.bentobox.api.events.island.IslandEvent;
|
||||
import world.bentobox.bentobox.api.flags.Flag;
|
||||
import world.bentobox.bentobox.api.localization.TextVariables;
|
||||
import world.bentobox.bentobox.api.logs.LogEntry;
|
||||
import world.bentobox.bentobox.api.metadata.MetaDataAble;
|
||||
import world.bentobox.bentobox.api.metadata.MetaDataValue;
|
||||
import world.bentobox.bentobox.api.user.User;
|
||||
import world.bentobox.bentobox.database.objects.adapters.Adapter;
|
||||
import world.bentobox.bentobox.database.objects.adapters.FlagSerializer;
|
||||
@ -54,7 +56,7 @@ import world.bentobox.bentobox.util.Util;
|
||||
* @author Poslovitch
|
||||
*/
|
||||
@Table(name = "Islands")
|
||||
public class Island implements DataObject {
|
||||
public class Island implements DataObject, MetaDataAble {
|
||||
|
||||
// True if this island is deleted and pending deletion from the database
|
||||
@Expose
|
||||
@ -171,6 +173,13 @@ public class Island implements DataObject {
|
||||
@Nullable
|
||||
private Boolean reserved = null;
|
||||
|
||||
/**
|
||||
* A place to store meta data for this island.
|
||||
* @since 1.15.4
|
||||
*/
|
||||
@Expose
|
||||
private Map<String, MetaDataValue> metaData;
|
||||
|
||||
/*
|
||||
* *************************** Constructors ******************************
|
||||
*/
|
||||
@ -1251,4 +1260,55 @@ public class Island implements DataObject {
|
||||
+ ", levelHandicap=" + levelHandicap + ", spawnPoint=" + spawnPoint + ", doNotLoad=" + doNotLoad + "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the metaData
|
||||
* @since 1.15.4
|
||||
*/
|
||||
@Override
|
||||
public Map<String, MetaDataValue> getMetaData() {
|
||||
return metaData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get meta data by key
|
||||
* @param key - key
|
||||
* @return the value to which the specified key is mapped, or null if there is no mapping for the key
|
||||
* @since 1.15.4
|
||||
*/
|
||||
@Override
|
||||
public MetaDataValue getMetaData(String key) {
|
||||
return this.metaData.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param metaData the metaData to set
|
||||
* @since 1.15.4
|
||||
*/
|
||||
@Override
|
||||
public void setMetaData(Map<String, MetaDataValue> metaData) {
|
||||
this.metaData = metaData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put a key, value string pair into the island's meta data
|
||||
* @param key - key
|
||||
* @param value - value
|
||||
* @return the previous value associated with key, or null if there was no mapping for key.
|
||||
* @since 1.15.4
|
||||
*/
|
||||
@Override
|
||||
public MetaDataValue putMetaData(String key, MetaDataValue value) {
|
||||
return this.metaData.put(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove meta data
|
||||
* @param key - key to remove
|
||||
* @return the previous value associated with key, or null if there was no mapping for key.
|
||||
* @since 1.15.4
|
||||
*/
|
||||
@Override
|
||||
public MetaDataValue removeMetaData(String key) {
|
||||
return this.metaData.remove(key);
|
||||
}
|
||||
}
|
||||
|
@ -11,12 +11,15 @@ import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.eclipse.jdt.annotation.NonNull;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
|
||||
import world.bentobox.bentobox.BentoBox;
|
||||
import world.bentobox.bentobox.api.flags.Flag;
|
||||
import world.bentobox.bentobox.api.metadata.MetaDataAble;
|
||||
import world.bentobox.bentobox.api.metadata.MetaDataValue;
|
||||
import world.bentobox.bentobox.util.Util;
|
||||
|
||||
/**
|
||||
@ -25,7 +28,7 @@ import world.bentobox.bentobox.util.Util;
|
||||
* @author tastybento
|
||||
*/
|
||||
@Table(name = "Players")
|
||||
public class Players implements DataObject {
|
||||
public class Players implements DataObject, MetaDataAble {
|
||||
@Expose
|
||||
private Map<Location, Integer> homeLocations = new HashMap<>();
|
||||
@Expose
|
||||
@ -53,6 +56,13 @@ public class Players implements DataObject {
|
||||
@Expose
|
||||
private Flag.Mode flagsDisplayMode = Flag.Mode.BASIC;
|
||||
|
||||
/**
|
||||
* A place to store meta data for this player.
|
||||
* @since 1.15.4
|
||||
*/
|
||||
@Expose
|
||||
private Map<String, MetaDataValue> metaData;
|
||||
|
||||
/**
|
||||
* This is required for database storage
|
||||
*/
|
||||
@ -338,4 +348,59 @@ public class Players implements DataObject {
|
||||
public void setFlagsDisplayMode(Flag.Mode flagsDisplayMode) {
|
||||
this.flagsDisplayMode = flagsDisplayMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the metaData
|
||||
*/
|
||||
@Override
|
||||
public Map<String, MetaDataValue> getMetaData() {
|
||||
if (metaData == null) {
|
||||
metaData = new HashMap<>();
|
||||
}
|
||||
return metaData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get meta data by key
|
||||
* @param key - key
|
||||
* @return the value to which the specified key is mapped, or null if there is no mapping for the key
|
||||
* @since 1.15.4
|
||||
*/
|
||||
@Override
|
||||
public MetaDataValue getMetaData(@NonNull String key) {
|
||||
return getMetaData().get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param metaData the metaData to set
|
||||
* @since 1.15.4
|
||||
*/
|
||||
@Override
|
||||
public void setMetaData(Map<String, MetaDataValue> metaData) {
|
||||
this.metaData = metaData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put a key, value string pair into the player's meta data
|
||||
* @param key - key
|
||||
* @param value - value
|
||||
* @return the previous value associated with key, or null if there was no mapping for key.
|
||||
* @since 1.15.4
|
||||
*/
|
||||
@Override
|
||||
public MetaDataValue putMetaData(@NonNull String key, @NonNull MetaDataValue value) {
|
||||
return getMetaData().put(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove meta data
|
||||
* @param key - key to remove
|
||||
* @return the previous value associated with key, or null if there was no mapping for key.
|
||||
* @since 1.15.4
|
||||
*/
|
||||
@Override
|
||||
public MetaDataValue removeMetaData(@NonNull String key) {
|
||||
return getMetaData().remove(key);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,92 @@
|
||||
package world.bentobox.bentobox.api.metadata;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.powermock.modules.junit4.PowerMockRunner;
|
||||
|
||||
/**
|
||||
* @author tastybento
|
||||
*
|
||||
*/
|
||||
@RunWith(PowerMockRunner.class)
|
||||
public class MetaDataValueTest {
|
||||
|
||||
/**
|
||||
* Test method for {@link world.bentobox.bentobox.api.metadata.MetaDataValue#asInt()}.
|
||||
*/
|
||||
@Test
|
||||
public void testAsInt() {
|
||||
MetaDataValue mdv = new MetaDataValue(123);
|
||||
assertEquals(123, mdv.asInt());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link world.bentobox.bentobox.api.metadata.MetaDataValue#asFloat()}.
|
||||
*/
|
||||
@Test
|
||||
public void testAsFloat() {
|
||||
MetaDataValue mdv = new MetaDataValue(123.34F);
|
||||
assertEquals(123.34F, mdv.asFloat(), 0F);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link world.bentobox.bentobox.api.metadata.MetaDataValue#asDouble()}.
|
||||
*/
|
||||
@Test
|
||||
public void testAsDouble() {
|
||||
MetaDataValue mdv = new MetaDataValue(123.3444D);
|
||||
assertEquals(123.3444D, mdv.asDouble(), 0D);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link world.bentobox.bentobox.api.metadata.MetaDataValue#asLong()}.
|
||||
*/
|
||||
@Test
|
||||
public void testAsLong() {
|
||||
MetaDataValue mdv = new MetaDataValue(123456L);
|
||||
assertEquals(123456L, mdv.asLong());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link world.bentobox.bentobox.api.metadata.MetaDataValue#asShort()}.
|
||||
*/
|
||||
@Test
|
||||
public void testAsShort() {
|
||||
MetaDataValue mdv = new MetaDataValue((short)12);
|
||||
assertEquals((short)12, mdv.asShort());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link world.bentobox.bentobox.api.metadata.MetaDataValue#asByte()}.
|
||||
*/
|
||||
@Test
|
||||
public void testAsByte() {
|
||||
MetaDataValue mdv = new MetaDataValue((byte)12);
|
||||
assertEquals((byte)12, mdv.asByte());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link world.bentobox.bentobox.api.metadata.MetaDataValue#asBoolean()}.
|
||||
*/
|
||||
@Test
|
||||
public void testAsBoolean() {
|
||||
MetaDataValue mdv = new MetaDataValue(false);
|
||||
assertFalse(mdv.asBoolean());
|
||||
mdv = new MetaDataValue(true);
|
||||
assertTrue(mdv.asBoolean());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link world.bentobox.bentobox.api.metadata.MetaDataValue#asString()}.
|
||||
*/
|
||||
@Test
|
||||
public void testAsString() {
|
||||
MetaDataValue mdv = new MetaDataValue("a string");
|
||||
assertEquals("a string", mdv.asString());
|
||||
}
|
||||
|
||||
}
|
@ -15,6 +15,7 @@ import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Optional;
|
||||
@ -33,6 +34,7 @@ import org.bukkit.inventory.ItemFactory;
|
||||
import org.bukkit.inventory.PlayerInventory;
|
||||
import org.bukkit.permissions.PermissionAttachmentInfo;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@ -49,6 +51,8 @@ import world.bentobox.bentobox.BentoBox;
|
||||
import world.bentobox.bentobox.Settings;
|
||||
import world.bentobox.bentobox.api.addons.AddonDescription;
|
||||
import world.bentobox.bentobox.api.addons.GameModeAddon;
|
||||
import world.bentobox.bentobox.api.metadata.MetaDataValue;
|
||||
import world.bentobox.bentobox.database.objects.Players;
|
||||
import world.bentobox.bentobox.managers.IslandWorldManager;
|
||||
import world.bentobox.bentobox.managers.LocalesManager;
|
||||
import world.bentobox.bentobox.managers.PlaceholdersManager;
|
||||
@ -80,6 +84,7 @@ public class UserTest {
|
||||
private Server server;
|
||||
@Mock
|
||||
private PlayersManager pm;
|
||||
private @Nullable Players players;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
@ -120,6 +125,8 @@ public class UserTest {
|
||||
when(placeholdersManager.replacePlaceholders(any(), any())).thenAnswer((Answer<String>) invocation -> invocation.getArgument(1, String.class));
|
||||
|
||||
when(plugin.getPlayers()).thenReturn(pm);
|
||||
players = new Players();
|
||||
when(pm.getPlayer(any())).thenReturn(players);
|
||||
}
|
||||
|
||||
@After
|
||||
@ -592,4 +599,30 @@ public class UserTest {
|
||||
User u = User.getInstance(player);
|
||||
assertEquals(3, u.getPermissionValue("bskyblock.max", 22));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMetaData() {
|
||||
User u = User.getInstance(player);
|
||||
assertTrue(u.getMetaData().isEmpty());
|
||||
// Store a string in a new key
|
||||
assertFalse(u.putMetaData("string", new MetaDataValue("a string")).isPresent());
|
||||
// Store an int in a new key
|
||||
assertFalse(u.putMetaData("int", new MetaDataValue(1234)).isPresent());
|
||||
// Overwrite the string with the same key
|
||||
assertEquals("a string", u.putMetaData("string", new MetaDataValue("a new string")).get().asString());
|
||||
// Get the new string with the same key
|
||||
assertEquals("a new string", u.getMetaData("string").get().asString());
|
||||
// Try to get a non-existent key
|
||||
assertFalse(u.getMetaData("boogie").isPresent());
|
||||
// Remove existing key
|
||||
assertEquals(1234, u.removeMetaData("int").get().asInt());
|
||||
assertFalse(u.getMetaData("int").isPresent());
|
||||
// Try to remove non-existent key
|
||||
assertFalse(u.removeMetaData("ggogg").isPresent());
|
||||
// Set the meta data as blank
|
||||
assertFalse(u.getMetaData().isEmpty());
|
||||
u.setMetaData(new HashMap<>());
|
||||
assertTrue(u.getMetaData().isEmpty());
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user