Refactoring to create less redundant code

This commit is contained in:
snowleo 2011-12-06 15:38:14 +01:00
parent 51390a9698
commit a7097df231
7 changed files with 330 additions and 175 deletions

View file

@ -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();
}
}
}

View file

@ -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();
}

View file

@ -1,7 +1,9 @@
package com.earth2me.essentials.user; package com.earth2me.essentials.user;
import com.earth2me.essentials.storage.IStorageObjectHolder;
public interface IOfflineUser extends IUserData, IOfflinePlayer
public interface IOfflineUser extends IStorageObjectHolder<UserData>, IOfflinePlayer
{ {
} }

View file

@ -1,13 +0,0 @@
package com.earth2me.essentials.user;
public interface IUserData
{
UserData getData();
void aquireReadLock();
void aquireWriteLock();
void close();
}

View file

@ -1,19 +1,16 @@
package com.earth2me.essentials.user; package com.earth2me.essentials.user;
import com.earth2me.essentials.IEssentials; import com.earth2me.essentials.IEssentials;
import com.earth2me.essentials.storage.AbstractDelayedYamlFileWriter; import com.earth2me.essentials.IUser;
import com.earth2me.essentials.storage.StorageObject; import com.earth2me.essentials.commands.IEssentialsCommand;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import lombok.Cleanup; import lombok.Cleanup;
import org.bukkit.Location;
import org.bukkit.OfflinePlayer; import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player; 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) public User(final Player base, final IEssentials ess)
{ {
super(base, ess); super(base, ess);
@ -24,43 +21,6 @@ public class User extends UserBase implements IOfflineUser
super(offlinePlayer, ess); super(offlinePlayer, ess);
} }
@Override
public UserData getData()
{
return data;
}
@Override
public void aquireReadLock()
{
rwl.readLock().lock();
}
@Override
public void aquireWriteLock()
{
while (rwl.getReadHoldCount() > 0)
{
rwl.readLock().unlock();
}
rwl.writeLock().lock();
rwl.readLock().lock();
}
@Override
public void close()
{
if (rwl.isWriteLockedByCurrentThread())
{
rwl.writeLock().unlock();
scheduleSaving();
}
while (rwl.getReadHoldCount() > 0)
{
rwl.readLock().unlock();
}
}
public void example() public void example()
{ {
// Cleanup will call close at the end of the function // Cleanup will call close at the end of the function
@ -68,37 +28,151 @@ public class User extends UserBase implements IOfflineUser
final User user = this; final User user = this;
// read lock allows to read data from the user // read lock allows to read data from the user
user.aquireReadLock(); user.acquireReadLock();
final double money = user.getData().getMoney(); final double money = user.getData().getMoney();
// write lock allows only one thread to modify the data // write lock allows only one thread to modify the data
user.aquireWriteLock(); user.acquireWriteLock();
user.getData().setMoney(10 + money); user.getData().setMoney(10 + money);
} }
private void scheduleSaving() @Override
public long getLastTeleportTimestamp()
{ {
new UserDataWriter(); acquireReadLock();
try
{
return getData().getTimestamps().get("lastteleport");
}
finally
{
unlock();
}
} }
private class UserDataWriter extends AbstractDelayedYamlFileWriter @Override
public boolean isAuthorized(String node)
{ {
public UserDataWriter() throw new UnsupportedOperationException("Not supported yet.");
{ }
super(ess, ess.getUserMap().getUserFile(User.this.getName()));
}
@Override @Override
public StorageObject getObject() public boolean isAuthorized(IEssentialsCommand cmd)
{ {
aquireReadLock(); throw new UnsupportedOperationException("Not supported yet.");
return getData(); }
}
@Override @Override
public void onFinish() public boolean isAuthorized(IEssentialsCommand cmd, String permissionPrefix)
{
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void setLastTeleportTimestamp(long time)
{
acquireWriteLock();
try
{ {
close(); getData().getTimestamps().put("lastteleport", time);
} }
finally
{
unlock();
}
}
@Override
public Location getLastLocation()
{
acquireReadLock();
try
{
return getData().getLastLocation();
}
finally
{
unlock();
}
}
@Override
public double getMoney()
{
acquireReadLock();
try
{
return getData().getMoney();
}
finally
{
unlock();
}
}
@Override
public void takeMoney(double value)
{
acquireWriteLock();
try
{
getData().setMoney(getData().getMoney() - value);
}
finally
{
unlock();
}
}
@Override
public void giveMoney(double value)
{
acquireWriteLock();
try
{
getData().setMoney(getData().getMoney() + value);
}
finally
{
unlock();
}
}
@Override
public String getGroup()
{
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void setLastLocation()
{
acquireWriteLock();
try
{
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.");
} }
} }

View file

@ -2,6 +2,8 @@ package com.earth2me.essentials.user;
import com.earth2me.essentials.IEssentials; import com.earth2me.essentials.IEssentials;
import com.earth2me.essentials.craftbukkit.OfflineBedLocation; import com.earth2me.essentials.craftbukkit.OfflineBedLocation;
import com.earth2me.essentials.storage.AsyncStorageObjectHolder;
import java.io.File;
import lombok.Delegate; import lombok.Delegate;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
@ -16,7 +18,7 @@ import org.bukkit.permissions.ServerOperator;
import org.bukkit.OfflinePlayer; import org.bukkit.OfflinePlayer;
public class UserBase implements Player, IOfflinePlayer public class UserBase extends AsyncStorageObjectHolder<UserData> implements Player, IOfflineUser
{ {
@Delegate(types = @Delegate(types =
@ -27,18 +29,19 @@ public class UserBase implements Player, IOfflinePlayer
},excludes=IOfflinePlayer.class) },excludes=IOfflinePlayer.class)
protected Player base; protected Player base;
protected transient OfflinePlayer offlinePlayer; protected transient OfflinePlayer offlinePlayer;
protected final transient IEssentials ess;
public UserBase(final Player base, final IEssentials ess) public UserBase(final Player base, final IEssentials ess)
{ {
super(ess, UserData.class);
this.base = base; this.base = base;
this.ess = ess; reloadConfig();
} }
public UserBase(final OfflinePlayer offlinePlayer, final IEssentials ess) public UserBase(final OfflinePlayer offlinePlayer, final IEssentials ess)
{ {
super(ess, UserData.class);
this.offlinePlayer = offlinePlayer; this.offlinePlayer = offlinePlayer;
this.ess = ess; reloadConfig();
} }
public final Player getBase() public final Player getBase()
@ -111,5 +114,9 @@ public class UserBase implements Player, IOfflinePlayer
} }
} }
@Override
public File getStorageFile()
{
return ess.getUserMap().getUserFile(getName());
}
} }

View file

@ -1,57 +1,46 @@
package com.earth2me.essentials.spawn; package com.earth2me.essentials.spawn;
import com.earth2me.essentials.IConf;
import com.earth2me.essentials.IEssentials; import com.earth2me.essentials.IEssentials;
import com.earth2me.essentials.IEssentialsModule; import com.earth2me.essentials.IEssentialsModule;
import com.earth2me.essentials.settings.Spawns; import com.earth2me.essentials.settings.Spawns;
import com.earth2me.essentials.storage.AbstractDelayedYamlFileReader; import com.earth2me.essentials.storage.AsyncStorageObjectHolder;
import com.earth2me.essentials.storage.AbstractDelayedYamlFileWriter;
import com.earth2me.essentials.storage.ObjectLoadException;
import com.earth2me.essentials.storage.StorageObject;
import java.io.File; import java.io.File;
import java.util.HashMap; import java.util.HashMap;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.World; 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) public SpawnStorage(final IEssentials ess)
{ {
this.ess = ess; super(ess, Spawns.class);
spawnfile = new File(ess.getDataFolder(), "spawn.yml"); reloadConfig();
new SpawnReader(); }
@Override
public File getStorageFile()
{
return new File(ess.getDataFolder(), "spawn.yml");
} }
public void setSpawn(final Location loc, final String group) public void setSpawn(final Location loc, final String group)
{ {
rwl.writeLock().lock(); acquireWriteLock();
try try
{ {
if (spawns == null) if (getData().getSpawns() == null)
{ {
spawns = new Spawns(); getData().setSpawns(new HashMap<String, Location>());
} }
if (spawns.getSpawns() == null) getData().getSpawns().put(group.toLowerCase(Locale.ENGLISH), loc);
{
spawns.setSpawns(new HashMap<String, Location>());
}
spawns.getSpawns().put(group.toLowerCase(Locale.ENGLISH), loc);
} }
finally finally
{ {
rwl.writeLock().unlock(); unlock();
} }
new SpawnWriter();
if ("default".equalsIgnoreCase(group)) if ("default".equalsIgnoreCase(group))
{ {
@ -61,14 +50,14 @@ public class SpawnStorage implements IConf, IEssentialsModule
public Location getSpawn(final String group) public Location getSpawn(final String group)
{ {
rwl.readLock().lock(); acquireReadLock();
try try
{ {
if (spawns == null || spawns.getSpawns() == null || group == null) if (getData().getSpawns() == null || group == null)
{ {
return getWorldSpawn(); return getWorldSpawn();
} }
final Map<String, Location> spawnMap = spawns.getSpawns(); final Map<String, Location> spawnMap = getData().getSpawns();
String groupName = group.toLowerCase(Locale.ENGLISH); String groupName = group.toLowerCase(Locale.ENGLISH);
if (!spawnMap.containsKey(groupName)) if (!spawnMap.containsKey(groupName))
{ {
@ -82,7 +71,7 @@ public class SpawnStorage implements IConf, IEssentialsModule
} }
finally finally
{ {
rwl.readLock().unlock(); unlock();
} }
} }
@ -98,66 +87,4 @@ public class SpawnStorage implements IConf, IEssentialsModule
} }
return ess.getServer().getWorlds().get(0).getSpawnLocation(); 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();
}
}
} }