diff options
7 files changed, 315 insertions, 160 deletions
diff --git a/Essentials/src/com/earth2me/essentials/storage/AsyncStorageObjectHolder.java b/Essentials/src/com/earth2me/essentials/storage/AsyncStorageObjectHolder.java new file mode 100644 index 000000000..bf3301e41 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/storage/AsyncStorageObjectHolder.java @@ -0,0 +1,141 @@ +package com.earth2me.essentials.storage; + +import com.earth2me.essentials.IConf; +import com.earth2me.essentials.IEssentials; +import java.io.File; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.logging.Level; +import org.bukkit.Bukkit; + + +public abstract class AsyncStorageObjectHolder<T extends StorageObject> implements IConf, IStorageObjectHolder<T> +{ + private transient T data; + private final transient ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); + private final transient Class<T> clazz; + protected final transient IEssentials ess; + + public AsyncStorageObjectHolder(final IEssentials ess, final Class<T> clazz) + { + this.ess = ess; + this.clazz = clazz; + try + { + this.data = clazz.newInstance(); + } + catch (Exception ex) + { + Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex); + } + } + + public T getData() + { + return data; + } + + public void acquireReadLock() + { + rwl.readLock().lock(); + } + + public void acquireWriteLock() + { + while (rwl.getReadHoldCount() > 0) + { + rwl.readLock().unlock(); + } + rwl.writeLock().lock(); + rwl.readLock().lock(); + } + + public void close() + { + unlock(); + } + + public void unlock() + { + if (rwl.isWriteLockedByCurrentThread()) + { + rwl.writeLock().unlock(); + new StorageObjectDataWriter(); + } + while (rwl.getReadHoldCount() > 0) + { + rwl.readLock().unlock(); + } + } + + @Override + public void reloadConfig() + { + new StorageObjectDataReader(); + } + + public abstract File getStorageFile(); + + + private class StorageObjectDataWriter extends AbstractDelayedYamlFileWriter + { + public StorageObjectDataWriter() + { + super(ess, getStorageFile()); + } + + @Override + public StorageObject getObject() + { + acquireReadLock(); + return getData(); + } + + @Override + public void onFinish() + { + unlock(); + } + } + + + private class StorageObjectDataReader extends AbstractDelayedYamlFileReader<T> + { + public StorageObjectDataReader() + { + super(ess, getStorageFile(), clazz); + } + + @Override + public void onStart() + { + rwl.writeLock().lock(); + } + + @Override + public void onSuccess(final T object) + { + if (object != null) + { + data = object; + } + rwl.writeLock().unlock(); + } + + @Override + public void onException() + { + if (data == null) + { + try + { + data = clazz.newInstance(); + } + catch (Exception ex) + { + Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex); + } + } + rwl.writeLock().unlock(); + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/storage/IStorageObjectHolder.java b/Essentials/src/com/earth2me/essentials/storage/IStorageObjectHolder.java new file mode 100644 index 000000000..f48e54002 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/storage/IStorageObjectHolder.java @@ -0,0 +1,17 @@ +package com.earth2me.essentials.storage; + +import com.earth2me.essentials.user.UserData; + + +public interface IStorageObjectHolder<T extends StorageObject> +{ + T getData(); + + void acquireReadLock(); + + void acquireWriteLock(); + + void close(); + + void unlock(); +} diff --git a/Essentials/src/com/earth2me/essentials/user/IOfflineUser.java b/Essentials/src/com/earth2me/essentials/user/IOfflineUser.java index 4ff54b37b..d6266df49 100644 --- a/Essentials/src/com/earth2me/essentials/user/IOfflineUser.java +++ b/Essentials/src/com/earth2me/essentials/user/IOfflineUser.java @@ -1,7 +1,9 @@ package com.earth2me.essentials.user; +import com.earth2me.essentials.storage.IStorageObjectHolder; -public interface IOfflineUser extends IUserData, IOfflinePlayer + +public interface IOfflineUser extends IStorageObjectHolder<UserData>, IOfflinePlayer { } diff --git a/Essentials/src/com/earth2me/essentials/user/IUserData.java b/Essentials/src/com/earth2me/essentials/user/IUserData.java deleted file mode 100644 index dcaeaf1a7..000000000 --- a/Essentials/src/com/earth2me/essentials/user/IUserData.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.earth2me.essentials.user; - - -public interface IUserData -{ - UserData getData(); - - void aquireReadLock(); - - void aquireWriteLock(); - - void close(); -} diff --git a/Essentials/src/com/earth2me/essentials/user/User.java b/Essentials/src/com/earth2me/essentials/user/User.java index 55740134f..89e664252 100644 --- a/Essentials/src/com/earth2me/essentials/user/User.java +++ b/Essentials/src/com/earth2me/essentials/user/User.java @@ -1,19 +1,16 @@ package com.earth2me.essentials.user; import com.earth2me.essentials.IEssentials; -import com.earth2me.essentials.storage.AbstractDelayedYamlFileWriter; -import com.earth2me.essentials.storage.StorageObject; -import java.util.concurrent.locks.ReentrantReadWriteLock; +import com.earth2me.essentials.IUser; +import com.earth2me.essentials.commands.IEssentialsCommand; import lombok.Cleanup; +import org.bukkit.Location; import org.bukkit.OfflinePlayer; import org.bukkit.entity.Player; -// this is a prototype for locking userdata -public class User extends UserBase implements IOfflineUser -{ - private transient UserData data = new UserData(); - private final transient ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); +public class User extends UserBase implements IUser +{ public User(final Player base, final IEssentials ess) { super(base, ess); @@ -24,81 +21,158 @@ public class User extends UserBase implements IOfflineUser super(offlinePlayer, ess); } + public void example() + { + // Cleanup will call close at the end of the function + @Cleanup + final User user = this; + + // read lock allows to read data from the user + user.acquireReadLock(); + final double money = user.getData().getMoney(); + + // write lock allows only one thread to modify the data + user.acquireWriteLock(); + user.getData().setMoney(10 + money); + } + + @Override + public long getLastTeleportTimestamp() + { + acquireReadLock(); + try + { + return getData().getTimestamps().get("lastteleport"); + } + finally + { + unlock(); + } + } + + @Override + public boolean isAuthorized(String node) + { + throw new UnsupportedOperationException("Not supported yet."); + } + @Override - public UserData getData() + public boolean isAuthorized(IEssentialsCommand cmd) { - return data; + throw new UnsupportedOperationException("Not supported yet."); } @Override - public void aquireReadLock() + public boolean isAuthorized(IEssentialsCommand cmd, String permissionPrefix) { - rwl.readLock().lock(); + throw new UnsupportedOperationException("Not supported yet."); } @Override - public void aquireWriteLock() + public void setLastTeleportTimestamp(long time) { - while (rwl.getReadHoldCount() > 0) + acquireWriteLock(); + try { - rwl.readLock().unlock(); + getData().getTimestamps().put("lastteleport", time); + } + finally + { + unlock(); } - rwl.writeLock().lock(); - rwl.readLock().lock(); } @Override - public void close() + public Location getLastLocation() { - if (rwl.isWriteLockedByCurrentThread()) + acquireReadLock(); + try { - rwl.writeLock().unlock(); - scheduleSaving(); + return getData().getLastLocation(); } - while (rwl.getReadHoldCount() > 0) + finally { - rwl.readLock().unlock(); + unlock(); } } - public void example() + @Override + public double getMoney() { - // Cleanup will call close at the end of the function - @Cleanup - final User user = this; - - // read lock allows to read data from the user - user.aquireReadLock(); - final double money = user.getData().getMoney(); - - // write lock allows only one thread to modify the data - user.aquireWriteLock(); - user.getData().setMoney(10 + money); + acquireReadLock(); + try + { + return getData().getMoney(); + } + finally + { + unlock(); + } } - private void scheduleSaving() + @Override + public void takeMoney(double value) { - new UserDataWriter(); + acquireWriteLock(); + try + { + getData().setMoney(getData().getMoney() - value); + } + finally + { + unlock(); + } } - private class UserDataWriter extends AbstractDelayedYamlFileWriter + @Override + public void giveMoney(double value) { - public UserDataWriter() + acquireWriteLock(); + try { - super(ess, ess.getUserMap().getUserFile(User.this.getName())); + getData().setMoney(getData().getMoney() + value); } - - @Override - public StorageObject getObject() + finally { - aquireReadLock(); - return getData(); + unlock(); } + } + + @Override + public String getGroup() + { + throw new UnsupportedOperationException("Not supported yet."); + } - @Override - public void onFinish() + @Override + public void setLastLocation() + { + acquireWriteLock(); + try { - close(); + getData().setLastLocation(base.getLocation()); } + finally + { + unlock(); + } + } + + @Override + public Location getHome(String name) throws Exception + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Location getHome(Location loc) throws Exception + { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isHidden() + { + throw new UnsupportedOperationException("Not supported yet."); } } diff --git a/Essentials/src/com/earth2me/essentials/user/UserBase.java b/Essentials/src/com/earth2me/essentials/user/UserBase.java index cc071817e..c215ebee9 100644 --- a/Essentials/src/com/earth2me/essentials/user/UserBase.java +++ b/Essentials/src/com/earth2me/essentials/user/UserBase.java @@ -2,6 +2,8 @@ package com.earth2me.essentials.user; import com.earth2me.essentials.IEssentials; import com.earth2me.essentials.craftbukkit.OfflineBedLocation; +import com.earth2me.essentials.storage.AsyncStorageObjectHolder; +import java.io.File; import lombok.Delegate; import org.bukkit.Bukkit; import org.bukkit.Location; @@ -16,7 +18,7 @@ import org.bukkit.permissions.ServerOperator; import org.bukkit.OfflinePlayer; -public class UserBase implements Player, IOfflinePlayer +public class UserBase extends AsyncStorageObjectHolder<UserData> implements Player, IOfflineUser { @Delegate(types = @@ -27,18 +29,19 @@ public class UserBase implements Player, IOfflinePlayer },excludes=IOfflinePlayer.class) protected Player base; protected transient OfflinePlayer offlinePlayer; - protected final transient IEssentials ess; public UserBase(final Player base, final IEssentials ess) { + super(ess, UserData.class); this.base = base; - this.ess = ess; + reloadConfig(); } public UserBase(final OfflinePlayer offlinePlayer, final IEssentials ess) { + super(ess, UserData.class); this.offlinePlayer = offlinePlayer; - this.ess = ess; + reloadConfig(); } public final Player getBase() @@ -110,6 +113,10 @@ public class UserBase implements Player, IOfflinePlayer offlinePlayer.setBanned(bln); } } - - + + @Override + public File getStorageFile() + { + return ess.getUserMap().getUserFile(getName()); + } } diff --git a/EssentialsSpawn/src/com/earth2me/essentials/spawn/SpawnStorage.java b/EssentialsSpawn/src/com/earth2me/essentials/spawn/SpawnStorage.java index 02fb26c9b..088ee9052 100644 --- a/EssentialsSpawn/src/com/earth2me/essentials/spawn/SpawnStorage.java +++ b/EssentialsSpawn/src/com/earth2me/essentials/spawn/SpawnStorage.java @@ -1,57 +1,46 @@ package com.earth2me.essentials.spawn; -import com.earth2me.essentials.IConf; import com.earth2me.essentials.IEssentials; import com.earth2me.essentials.IEssentialsModule; import com.earth2me.essentials.settings.Spawns; -import com.earth2me.essentials.storage.AbstractDelayedYamlFileReader; -import com.earth2me.essentials.storage.AbstractDelayedYamlFileWriter; -import com.earth2me.essentials.storage.ObjectLoadException; -import com.earth2me.essentials.storage.StorageObject; +import com.earth2me.essentials.storage.AsyncStorageObjectHolder; import java.io.File; import java.util.HashMap; import java.util.Locale; import java.util.Map; -import java.util.concurrent.locks.ReentrantReadWriteLock; -import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.World; -public class SpawnStorage implements IConf, IEssentialsModule +public class SpawnStorage extends AsyncStorageObjectHolder<Spawns> implements IEssentialsModule { - private transient Spawns spawns; - private final transient IEssentials ess; - private final transient File spawnfile; - private final transient ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); - public SpawnStorage(final IEssentials ess) { - this.ess = ess; - spawnfile = new File(ess.getDataFolder(), "spawn.yml"); - new SpawnReader(); + super(ess, Spawns.class); + reloadConfig(); + } + + @Override + public File getStorageFile() + { + return new File(ess.getDataFolder(), "spawn.yml"); } public void setSpawn(final Location loc, final String group) { - rwl.writeLock().lock(); + acquireWriteLock(); try { - if (spawns == null) + if (getData().getSpawns() == null) { - spawns = new Spawns(); + getData().setSpawns(new HashMap<String, Location>()); } - if (spawns.getSpawns() == null) - { - spawns.setSpawns(new HashMap<String, Location>()); - } - spawns.getSpawns().put(group.toLowerCase(Locale.ENGLISH), loc); + getData().getSpawns().put(group.toLowerCase(Locale.ENGLISH), loc); } finally { - rwl.writeLock().unlock(); + unlock(); } - new SpawnWriter(); if ("default".equalsIgnoreCase(group)) { @@ -61,14 +50,14 @@ public class SpawnStorage implements IConf, IEssentialsModule public Location getSpawn(final String group) { - rwl.readLock().lock(); + acquireReadLock(); try { - if (spawns == null || spawns.getSpawns() == null || group == null) + if (getData().getSpawns() == null || group == null) { return getWorldSpawn(); } - final Map<String, Location> spawnMap = spawns.getSpawns(); + final Map<String, Location> spawnMap = getData().getSpawns(); String groupName = group.toLowerCase(Locale.ENGLISH); if (!spawnMap.containsKey(groupName)) { @@ -82,7 +71,7 @@ public class SpawnStorage implements IConf, IEssentialsModule } finally { - rwl.readLock().unlock(); + unlock(); } } @@ -98,66 +87,4 @@ public class SpawnStorage implements IConf, IEssentialsModule } return ess.getServer().getWorlds().get(0).getSpawnLocation(); } - - @Override - public void reloadConfig() - { - new SpawnReader(); - } - - - private class SpawnWriter extends AbstractDelayedYamlFileWriter - { - public SpawnWriter() - { - super(ess, spawnfile); - } - - @Override - public StorageObject getObject() - { - rwl.readLock().lock(); - return spawns; - } - - @Override - public void onFinish() - { - rwl.readLock().unlock(); - } - } - - - private class SpawnReader extends AbstractDelayedYamlFileReader<Spawns> - { - public SpawnReader() - { - super(ess, spawnfile, Spawns.class); - } - - @Override - public void onStart() - { - rwl.writeLock().lock(); - } - - @Override - public void onSuccess(final Spawns object) - { - if (object != null) - { - spawns = object; - } - rwl.writeLock().unlock(); - } - - @Override - public void onException() - { - if (spawns == null) { - spawns = new Spawns(); - } - rwl.writeLock().unlock(); - } - } } |