package com.sk89q.squirrelid.cache;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableMap;
import com.sk89q.squirrelid.Profile;
import com.supaham.commons.CMain;
import com.supaham.commons.database.JDBCAgent;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.UUID;
import java.util.logging.Level;
import javax.annotation.Nonnull;
/**
* Represents a MySQL implementation of {@link AbstractProfileCache}.
*
* @author SupaHam
* @since 0.1
*/
public class MySQLCache extends AbstractProfileCache {
public static final String TABLE_NAME = "uuid_cache";
private final JDBCAgent agent;
private final String tableName;
private final String queryString;
public MySQLCache(@Nonnull JDBCAgent jdbcAgent) throws SQLException {
this(jdbcAgent, TABLE_NAME);
}
public MySQLCache(@Nonnull JDBCAgent jdbcAgent, @Nonnull String tableName) throws SQLException {
checkNotNull(jdbcAgent);
// checkNotNullOrEmpty(tableName, "tableName");
this.agent = jdbcAgent;
this.tableName = tableName;
this.queryString = "REPLACE INTO `" + tableName + "` (uuid, name) VALUES (?, ?)";
createTable();
}
@Override
public void putAll(Iterable<Profile> iterable) {
try {
executePut(iterable);
} catch (SQLException e) {
CMain.getLogger().log(Level.WARNING, "Failed to execute queries", e);
}
}
@Override
public ImmutableMap<UUID, Profile> getAllPresent(Iterable<UUID> iterable) {
try {
return executeGet(iterable);
} catch (SQLException e) {
CMain.getLogger().log(Level.WARNING, "Failed to execute queries", e);
}
return ImmutableMap.of();
}
/**
* Create the necessary tables and indices if they do not exist yet.
*
* @throws SQLException thrown on error
*/
private void createTable() throws SQLException {
try (Connection conn = getConnection();
Statement stmt = conn.createStatement()) {
stmt.executeUpdate(
"CREATE TABLE IF NOT EXISTS `" + this.tableName + "` ("
+ "`uuid` CHAR(36) PRIMARY KEY NOT NULL, "
+ "`name` VARCHAR(16) NOT NULL UNIQUE KEY)");
} catch (SQLException e) {
throw new SQLException("Failed to create table.", e);
}
}
protected synchronized void executePut(Iterable<Profile> profiles) throws SQLException {
PreparedStatement stmt = preparedStatement();
for (Profile profile : profiles) {
stmt.setString(1, profile.getUniqueId().toString());
stmt.setString(2, profile.getName());
stmt.addBatch();
}
stmt.executeBatch();
}
protected ImmutableMap<UUID, Profile> executeGet(Iterable<UUID> uuids) throws SQLException {
Iterator<UUID> it = uuids.iterator();
// It was an empty collection
if (!it.hasNext()) {
return ImmutableMap.of();
}
StringBuilder builder = new StringBuilder();
// SELECT ... WHERE ... IN ('abc', 'def', 'ghi');
builder.append("SELECT name, uuid FROM `").append(this.tableName).append("` WHERE uuid IN ('");
Joiner.on("', '").skipNulls().appendTo(builder, uuids);
builder.append("');");
synchronized (this) {
try (Connection conn = getConnection();
Statement stmt = conn.createStatement()) {
ResultSet rs = stmt.executeQuery(builder.toString());
Map<UUID, Profile> map = new HashMap<>();
while (rs.next()) {
UUID uuid = UUID.fromString(rs.getString("uuid"));
map.put(uuid, new Profile(uuid, rs.getString("name")));
}
return ImmutableMap.copyOf(map);
}
}
}
private PreparedStatement preparedStatement() throws SQLException {
return getConnection().prepareStatement(queryString);
}
private Connection getConnection() throws SQLException {
return this.agent.getDataSource().getConnection();
}
}