Make DB code nicer

This commit is contained in:
Andrzej Pomirski 2015-05-22 13:26:07 +02:00
parent 6466b2d6aa
commit 02673dec94
7 changed files with 209 additions and 66 deletions

View File

@ -11,6 +11,7 @@ import java.util.UUID;
* @author Andrzej Pomirski (Acrobot)
*/
@DatabaseTable(tableName = "accounts")
@DatabaseFileName("users.db")
public class Account {
@DatabaseField(canBeNull = false)

View File

@ -0,0 +1,59 @@
package com.Acrobot.ChestShop.Database;
import com.Acrobot.ChestShop.ChestShop;
import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.dao.DaoManager;
import com.j256.ormlite.dao.LruObjectCache;
import com.j256.ormlite.db.SqliteDatabaseType;
import com.j256.ormlite.jdbc.JdbcConnectionSource;
import com.j256.ormlite.support.ConnectionSource;
import com.j256.ormlite.table.TableUtils;
import java.security.InvalidParameterException;
import java.sql.SQLException;
/**
* Creates a DAO appropriate for the plugin
*
* @author Andrzej Pomirski
*/
public class DaoCreator {
/**
* Returns a DAO for the given entity and with the given ID
* @param entity Entity's class
* @param <ENTITY> Type of the entity
* @return Dao
* @throws InvalidParameterException
* @throws SQLException
*/
public static <ENTITY, ID> Dao<ENTITY, ID> getDao(Class<ENTITY> entity) throws InvalidParameterException, SQLException {
if (!entity.isAnnotationPresent(DatabaseFileName.class)) {
throw new InvalidParameterException("Entity not annotated with @DatabaseFileName!");
}
String fileName = entity.getAnnotation(DatabaseFileName.class).value();
String uri = ConnectionManager.getURI(ChestShop.loadFile(fileName));
ConnectionSource connectionSource = new JdbcConnectionSource(uri, new SqliteDatabaseType());
Dao<ENTITY, ID> dao = DaoManager.createDao(connectionSource, entity);
dao.setObjectCache(new LruObjectCache(200));
return dao;
}
/**
* Creates a dao as well as a default table, if doesn't exist
* @see #getDao(Class)
* @throws SQLException
* @throws InvalidParameterException
*/
public static <ENTITY, ID> Dao<ENTITY, ID> getDaoAndCreateTable(Class<ENTITY> entity) throws SQLException, InvalidParameterException {
Dao<ENTITY, ID> dao = getDao(entity);
TableUtils.createTableIfNotExists(dao.getConnectionSource(), entity);
return dao;
}
}

View File

@ -0,0 +1,13 @@
package com.Acrobot.ChestShop.Database;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* Represents the filename of the database (inside ChestShop's folder)
* @author Andrzej Pomirski
*/
@Retention(RetentionPolicy.RUNTIME)
public @interface DatabaseFileName {
String value();
}

View File

@ -0,0 +1,39 @@
package com.Acrobot.ChestShop.Database;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
/**
* Mapping for enchanted items
* @author Andrzej Pomirski
*/
@DatabaseTable(tableName = "items")
@DatabaseFileName("items.db")
public class Item {
@DatabaseField(canBeNull = false, generatedId = true)
private int id;
@DatabaseField(columnName = "code", canBeNull = false, unique = true)
private String base64ItemCode;
public Item() {
//empty constructor
}
public Item(String base64ItemCode) {
this.base64ItemCode = base64ItemCode;
}
public int getId() {
return id;
}
public String getBase64ItemCode() {
return base64ItemCode;
}
public void setBase64ItemCode(String base64ItemCode) {
this.base64ItemCode = base64ItemCode;
}
}

View File

@ -0,0 +1,56 @@
package com.Acrobot.ChestShop.Database;
import com.Acrobot.ChestShop.ChestShop;
import com.j256.ormlite.dao.Dao;
import java.sql.SQLException;
/**
* File handling the database migrations
*
* @author Andrzej Pomirski
*/
public class Migrations {
public static final int CURRENT_DATABASE_VERSION = 2;
/**
* Migrates a database from the given version
*
* @param currentVersion Current version of the database
* @return Current database version
*/
public static int migrate(int currentVersion) {
if (currentVersion != CURRENT_DATABASE_VERSION) {
ChestShop.getBukkitLogger().info("Updating database...");
} else {
return CURRENT_DATABASE_VERSION;
}
switch (currentVersion) {
case 1:
boolean migrated = migrateTo2();
if (migrated) {
currentVersion++;
}
case 2:
default:
//do nothing
}
return currentVersion;
}
private static boolean migrateTo2() {
try {
Dao<Account, String> accounts = DaoCreator.getDao(Account.class);
accounts.executeRaw("ALTER TABLE `accounts` ADD COLUMN lastSeenName VARCHAR");
return true;
} catch (SQLException e) {
e.printStackTrace();
return false;
}
}
}

View File

@ -1,22 +1,19 @@
package com.Acrobot.ChestShop.Metadata;
import com.Acrobot.Breeze.Database.Database;
import com.Acrobot.Breeze.Database.Row;
import com.Acrobot.Breeze.Database.Table;
import com.Acrobot.Breeze.Utils.Encoding.Base62;
import com.Acrobot.Breeze.Utils.Encoding.Base64;
import com.Acrobot.ChestShop.ChestShop;
import com.Acrobot.ChestShop.Database.DaoCreator;
import com.Acrobot.ChestShop.Database.Item;
import com.j256.ormlite.dao.Dao;
import org.bukkit.configuration.file.YamlConstructor;
import org.bukkit.configuration.file.YamlRepresenter;
import org.bukkit.inventory.ItemStack;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.nodes.Tag;
import java.io.IOException;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Map;
/**
* Saves items with Metadata in database, which allows for saving items on signs easily.
@ -24,33 +21,15 @@ import java.util.Map;
* @author Acrobot
*/
public class ItemDatabase {
private static final Map<String, ItemStack> METADATA_CACHE = new HashMap<String, ItemStack>();
private Dao<Item, Integer> itemDao;
private final Yaml yaml;
private Table table;
public ItemDatabase() {
try {
Class.forName("org.sqlite.JDBC");
} catch (ClassNotFoundException e) {
e.printStackTrace();
ChestShop.getBukkitLogger().severe("You haven't got any SQLite JDBC installed!");
}
Database database = new Database("jdbc:sqlite:" + ChestShop.loadFile("items.db").getAbsolutePath());
yaml = new Yaml(new YamlConstructor(), new YamlRepresenter(), new DumperOptions());
yaml = new Yaml(new YamlBukkitConstructor(), new YamlRepresenter(), new DumperOptions());
try {
Statement statement = database.getConnection().createStatement();
statement.executeUpdate("PRAGMA user_version = 1"); //We'll be able to change it later if we need to
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
table = database.getTable("items");
table.create("id INTEGER PRIMARY KEY, code VARCHAR UNIQUE ON CONFLICT IGNORE");
itemDao = DaoCreator.getDaoAndCreateTable(Item.class);
} catch (SQLException e) {
e.printStackTrace();
}
@ -66,21 +45,29 @@ public class ItemDatabase {
try {
ItemStack clone = new ItemStack(item);
clone.setAmount(1);
clone.setDurability((short) 0);
String code = Base64.encodeObject(yaml.dump(clone));
table.insertRow("null, '" + code + '\'');
Item itemEntity = itemDao.queryBuilder().where().eq("code", code).queryForFirst();
if (itemEntity != null) {
return Base62.encode(itemEntity.getId());
}
itemEntity = new Item(code);
itemDao.create(itemEntity);
int id = itemEntity.getId();
int id = Integer.parseInt(table.getRow("code='" + code + '\'').get("id"));
return Base62.encode(id);
} catch (IOException e) {
e.printStackTrace();
return null;
} catch (SQLException e) {
e.printStackTrace();
return null;
} catch (IllegalArgumentException e) {
return null;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/**
@ -90,32 +77,32 @@ public class ItemDatabase {
* @return ItemStack represented by this code
*/
public ItemStack getFromCode(String code) {
if (METADATA_CACHE.containsKey(code)) {
return METADATA_CACHE.get(code);
}
try {
Row row = table.getRow("id='" + Base62.decode(code) + '\'');
int id = Base62.decode(code);
Item item = itemDao.queryBuilder().where().eq("id", id).queryForFirst();
if (row.getSize() == 0) {
if (item == null) {
return null;
}
String serialized = row.get("code");
String serialized = item.getBase64ItemCode();
ItemStack item = (ItemStack) yaml.load((String) Base64.decodeToObject(serialized));
METADATA_CACHE.put(code, item);
return item;
return yaml.loadAs((String) Base64.decodeToObject(serialized), ItemStack.class);
} catch (SQLException e) {
e.printStackTrace();
return null;
} catch (IOException e) {
e.printStackTrace();
return null;
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
private class YamlBukkitConstructor extends YamlConstructor {
public YamlBukkitConstructor() {
this.yamlConstructors.put(new Tag(Tag.PREFIX + "org.bukkit.inventory.ItemStack"), yamlConstructors.get(Tag.MAP));
}
}
}

View File

@ -1,23 +1,17 @@
package com.Acrobot.ChestShop.UUIDs;
import com.Acrobot.Breeze.Utils.NameUtil;
import com.Acrobot.ChestShop.ChestShop;
import com.Acrobot.ChestShop.Configuration.Properties;
import com.Acrobot.ChestShop.Database.Account;
import com.Acrobot.ChestShop.Database.ConnectionManager;
import com.Acrobot.ChestShop.Database.DaoCreator;
import com.Acrobot.ChestShop.Permission;
import com.Acrobot.ChestShop.Signs.ChestShopSign;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.dao.DaoManager;
import com.j256.ormlite.jdbc.JdbcConnectionSource;
import com.j256.ormlite.support.ConnectionSource;
import com.j256.ormlite.table.TableUtils;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import java.io.File;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
@ -28,6 +22,7 @@ import java.util.UUID;
*
* @author Andrzej Pomirski (Acrobot)
*/
@SuppressWarnings("UnusedAssignment") //I deliberately set the variables to null while initializing
public class NameManager {
private static Dao<Account, String> accounts;
@ -229,19 +224,12 @@ public class NameManager {
}
public static boolean isAdminShop(UUID uuid) {
return getUsername(uuid).equals(Properties.ADMIN_SHOP_NAME);
return Properties.ADMIN_SHOP_NAME.equals(getUsername(uuid));
}
public static void load() {
File databaseFile = ChestShop.loadFile("users.db");
String uri = ConnectionManager.getURI(databaseFile);
ConnectionSource connection;
try {
connection = new JdbcConnectionSource(uri);
accounts = DaoManager.createDao(connection, Account.class);
TableUtils.createTableIfNotExists(connection, Account.class);
accounts = DaoCreator.getDaoAndCreateTable(Account.class);
Account adminAccount = new Account(Properties.ADMIN_SHOP_NAME, Bukkit.getOfflinePlayer(Properties.ADMIN_SHOP_NAME).getUniqueId());
accounts.createOrUpdate(adminAccount);