More work done on config code

This commit is contained in:
snowleo 2011-12-06 10:37:17 +01:00
parent 6fe8e603af
commit f3b278eac2
13 changed files with 459 additions and 75 deletions

View File

@ -85,8 +85,7 @@ public class UserMap extends CacheLoader<String, User> implements IConf
return new User(player, ess);
}
}
final File userFolder = new File(ess.getDataFolder(), "userdata");
final File userFile = new File(userFolder, Util.sanitizeFileName(name) + ".yml");
final File userFile = getUserFile(name);
if (userFile.exists())
{
keys.add(name.toLowerCase(Locale.ENGLISH));
@ -116,4 +115,10 @@ public class UserMap extends CacheLoader<String, User> implements IConf
{
return keys.size();
}
public File getUserFile(final String name)
{
final File userFolder = new File(ess.getDataFolder(), "userdata");
return new File(userFolder, Util.sanitizeFileName(name) + ".yml");
}
}

View File

@ -0,0 +1,55 @@
package com.earth2me.essentials.storage;
import com.earth2me.essentials.IEssentials;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.bukkit.Bukkit;
public abstract class AbstractDelayedYamlFileWriter implements Runnable
{
private final transient File file;
public AbstractDelayedYamlFileWriter(IEssentials ess, File file)
{
this.file = file;
ess.scheduleAsyncDelayedTask(this);
}
public abstract StorageObject getObject();
@Override
public void run()
{
PrintWriter pw = null;
try
{
final StorageObject object = getObject();
final File folder = file.getParentFile();
if (!folder.exists())
{
folder.mkdirs();
}
pw = new PrintWriter(file);
new YamlStorageWriter(pw).save(object);
}
catch (FileNotFoundException ex)
{
Bukkit.getLogger().log(Level.SEVERE, file.toString(), ex);
}
finally
{
onFinish();
if (pw != null)
{
pw.close();
}
}
}
public abstract void onFinish();
}

View File

@ -1,4 +1,4 @@
package com.earth2me.essentials.userdata;
package com.earth2me.essentials.user;
import com.earth2me.essentials.storage.StorageObject;
import lombok.Data;

View File

@ -0,0 +1,15 @@
package com.earth2me.essentials.user;
import org.bukkit.Location;
public interface IOfflinePlayer
{
String getName();
String getDisplayName();
Location getBedSpawnLocation();
void setBanned(boolean bln);
}

View File

@ -0,0 +1,7 @@
package com.earth2me.essentials.user;
public interface IOfflineUser extends IUserData, IOfflinePlayer
{
}

View File

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

View File

@ -1,4 +1,4 @@
package com.earth2me.essentials.userdata;
package com.earth2me.essentials.user;
import com.earth2me.essentials.storage.MapKeyType;
import com.earth2me.essentials.storage.MapValueType;

View File

@ -0,0 +1,111 @@
package com.earth2me.essentials.user;
import com.earth2me.essentials.IEssentials;
import com.earth2me.essentials.storage.AbstractDelayedYamlFileWriter;
import com.earth2me.essentials.storage.StorageObject;
import com.earth2me.essentials.storage.YamlStorageReader;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import lombok.Cleanup;
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 User(final Player base, final IEssentials ess)
{
super(base, ess);
}
public User(final OfflinePlayer offlinePlayer, final IEssentials ess)
{
super(offlinePlayer, ess);
}
public void loadUserData()
{
data = new YamlStorageReader(null).load(UserData.class);
}
@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()
{
// 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);
}
private void scheduleSaving()
{
new UserDataWriter();
}
private class UserDataWriter extends AbstractDelayedYamlFileWriter
{
public UserDataWriter()
{
super(ess, ess.getUserMap().getUserFile(User.this.getName()));
}
@Override
public StorageObject getObject()
{
aquireReadLock();
return getData();
}
@Override
public void onFinish()
{
close();
}
}
}

View File

@ -0,0 +1,115 @@
package com.earth2me.essentials.user;
import com.earth2me.essentials.IEssentials;
import com.earth2me.essentials.craftbukkit.OfflineBedLocation;
import lombok.Delegate;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.serialization.ConfigurationSerializable;
import org.bukkit.entity.Entity;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.permissions.Permissible;
import org.bukkit.permissions.ServerOperator;
import org.bukkit.OfflinePlayer;
public class UserBase implements Player, IOfflinePlayer
{
@Delegate(types =
{
Player.class, Entity.class, CommandSender.class, ServerOperator.class,
HumanEntity.class, ConfigurationSerializable.class, LivingEntity.class,
Permissible.class
},excludes=IOfflinePlayer.class)
protected Player base;
protected transient OfflinePlayer offlinePlayer;
protected final transient IEssentials ess;
public UserBase(final Player base, final IEssentials ess)
{
this.base = base;
this.ess = ess;
}
public UserBase(final OfflinePlayer offlinePlayer, final IEssentials ess)
{
this.offlinePlayer = offlinePlayer;
this.ess = ess;
}
public final Player getBase()
{
return base;
}
public final Player setBase(final Player base)
{
return this.base = base;
}
public void update(final Player base)
{
setBase(base);
}
public void update(final OfflinePlayer offlinePlayer)
{
this.offlinePlayer = offlinePlayer;
}
public void dispose()
{
this.offlinePlayer = Bukkit.getOfflinePlayer(base.getName());
this.base = null;
}
public boolean isOnlineUser() {
return base != null;
}
@Override
public String getName()
{
if (isOnlineUser()) {
return base.getName();
} else {
return offlinePlayer.getName();
}
}
@Override
public String getDisplayName()
{
if (isOnlineUser()) {
return base.getDisplayName();
} else {
return offlinePlayer.getName();
}
}
@Override
public Location getBedSpawnLocation()
{
if (isOnlineUser()) {
return base.getBedSpawnLocation();
} else {
return OfflineBedLocation.getBedLocation(base.getName(), ess);
}
}
@Override
public void setBanned(boolean bln)
{
if (isOnlineUser()) {
base.setBanned(bln);
} else {
offlinePlayer.setBanned(bln);
}
}
}

View File

@ -1,4 +1,4 @@
package com.earth2me.essentials.userdata;
package com.earth2me.essentials.user;
import com.earth2me.essentials.storage.ListType;
import com.earth2me.essentials.storage.MapKeyType;

View File

@ -0,0 +1,128 @@
package com.earth2me.essentials.user;
import com.earth2me.essentials.IConf;
import com.earth2me.essentials.IEssentials;
import com.earth2me.essentials.Util;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.util.concurrent.UncheckedExecutionException;
import java.io.File;
import java.util.Collections;
import java.util.Locale;
import java.util.Set;
import java.util.concurrent.ConcurrentSkipListSet;
import java.util.concurrent.ExecutionException;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
public class UserMap extends CacheLoader<String, User> implements IConf
{
private final transient IEssentials ess;
private final transient Cache<String, User> users = CacheBuilder.newBuilder().softValues().build(this);
private final transient ConcurrentSkipListSet<String> keys = new ConcurrentSkipListSet<String>();
public UserMap(final IEssentials ess)
{
super();
this.ess = ess;
loadAllUsersAsync(ess);
}
private void loadAllUsersAsync(final IEssentials ess)
{
ess.scheduleAsyncDelayedTask(new Runnable()
{
@Override
public void run()
{
final File userdir = new File(ess.getDataFolder(), "userdata");
if (!userdir.exists())
{
return;
}
keys.clear();
users.invalidateAll();
for (String string : userdir.list())
{
if (!string.endsWith(".yml"))
{
continue;
}
final String name = string.substring(0, string.length() - 4);
keys.add(name.toLowerCase(Locale.ENGLISH));
}
}
});
}
public boolean userExists(final String name)
{
return keys.contains(name.toLowerCase(Locale.ENGLISH));
}
public User getUser(final String name)
{
try
{
return users.get(name.toLowerCase(Locale.ENGLISH));
}
catch (ExecutionException ex)
{
return null;
}
catch (UncheckedExecutionException ex)
{
return null;
}
}
@Override
public User load(final String name) throws Exception
{
for (Player player : ess.getServer().getOnlinePlayers())
{
if (player.getName().equalsIgnoreCase(name))
{
keys.add(name.toLowerCase(Locale.ENGLISH));
return new User(player, ess);
}
}
final File userFile = getUserFile(name);
if (userFile.exists())
{
keys.add(name.toLowerCase(Locale.ENGLISH));
return new User(Bukkit.getOfflinePlayer(name), ess);
}
throw new Exception("User not found!");
}
@Override
public void reloadConfig()
{
loadAllUsersAsync(ess);
}
public void removeUser(final String name)
{
keys.remove(name.toLowerCase(Locale.ENGLISH));
users.invalidate(name.toLowerCase(Locale.ENGLISH));
}
public Set<String> getAllUniqueUsers()
{
return Collections.unmodifiableSet(keys);
}
public int getUniqueUsers()
{
return keys.size();
}
public File getUserFile(final String name)
{
final File userFolder = new File(ess.getDataFolder(), "userdata");
return new File(userFolder, Util.sanitizeFileName(name) + ".yml");
}
}

View File

@ -1,65 +0,0 @@
package com.earth2me.essentials.userdata;
import com.earth2me.essentials.storage.YamlStorageReader;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import lombok.Cleanup;
// this is a prototype for locking userdata
public class User
{
UserData data = new UserData();
ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
public void loadUserData()
{
data = new YamlStorageReader(null).load(UserData.class);
}
public void aquireReadLock()
{
rwl.readLock().lock();
}
public void aquireWriteLock()
{
while (rwl.getReadHoldCount() > 0)
{
rwl.readLock().unlock();
}
rwl.writeLock().lock();
rwl.readLock().lock();
}
public void close()
{
if (rwl.isWriteLockedByCurrentThread())
{
scheduleSaving();
rwl.writeLock().unlock();
}
while (rwl.getReadHoldCount() > 0)
{
rwl.readLock().unlock();
}
}
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.aquireReadLock();
double i = user.data.getMoney();
// write lock allows only one thread to modify the data
user.aquireWriteLock();
user.data.setMoney(10 + user.data.getMoney());
}
private void scheduleSaving()
{
System.out.println("Schedule saving...");
}
}

View File

@ -80,11 +80,11 @@ public class StorageTest extends TestCase
ext.start();
final ByteArrayInputStream bais = new ByteArrayInputStream(new byte[0]);
final Reader reader = new InputStreamReader(bais);
final com.earth2me.essentials.userdata.UserData userdata = new YamlStorageReader(reader).load(com.earth2me.essentials.userdata.UserData.class);
final com.earth2me.essentials.user.UserData userdata = new YamlStorageReader(reader).load(com.earth2me.essentials.user.UserData.class);
ext.mark("load empty user");
final ByteArrayInputStream bais3 = new ByteArrayInputStream(new byte[0]);
final Reader reader3 = new InputStreamReader(bais3);
final com.earth2me.essentials.userdata.UserData userdata3 = new YamlStorageReader(reader3).load(com.earth2me.essentials.userdata.UserData.class);
final com.earth2me.essentials.user.UserData userdata3 = new YamlStorageReader(reader3).load(com.earth2me.essentials.user.UserData.class);
ext.mark("load empty user (class cached)");
for (int j = 0; j < 10000; j++)
@ -107,16 +107,16 @@ public class StorageTest extends TestCase
ext.mark("debug output");
final ByteArrayInputStream bais2 = new ByteArrayInputStream(written);
final Reader reader2 = new InputStreamReader(bais2);
final com.earth2me.essentials.userdata.UserData userdata2 = new YamlStorageReader(reader2).load(com.earth2me.essentials.userdata.UserData.class);
final com.earth2me.essentials.user.UserData userdata2 = new YamlStorageReader(reader2).load(com.earth2me.essentials.user.UserData.class);
ext.mark("reload file");
final ByteArrayInputStream bais4 = new ByteArrayInputStream(written);
final Reader reader4 = new InputStreamReader(bais4);
final com.earth2me.essentials.userdata.UserData userdata4 = new YamlStorageReader(reader4).load(com.earth2me.essentials.userdata.UserData.class);
final com.earth2me.essentials.user.UserData userdata4 = new YamlStorageReader(reader4).load(com.earth2me.essentials.user.UserData.class);
ext.mark("reload file (cached)");
System.out.println(userdata.toString());
System.out.println(userdata2.toString());
System.out.println(ext.end());
com.earth2me.essentials.userdata.User test = new com.earth2me.essentials.userdata.User();
com.earth2me.essentials.user.User test = new com.earth2me.essentials.user.User(null, ess);
test.example();
}