219 lines
8.1 KiB
Java
219 lines
8.1 KiB
Java
package world.bentobox.bentobox.database.yaml;
|
|
|
|
import java.io.BufferedReader;
|
|
import java.io.File;
|
|
import java.io.FileInputStream;
|
|
import java.io.FileOutputStream;
|
|
import java.io.IOException;
|
|
import java.io.InputStream;
|
|
import java.io.InputStreamReader;
|
|
import java.io.OutputStream;
|
|
import java.io.OutputStreamWriter;
|
|
import java.io.PrintWriter;
|
|
import java.io.Writer;
|
|
import java.nio.charset.StandardCharsets;
|
|
import java.nio.file.Files;
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Map.Entry;
|
|
import java.util.Objects;
|
|
import java.util.Scanner;
|
|
import java.util.UUID;
|
|
|
|
import org.bukkit.configuration.InvalidConfigurationException;
|
|
import org.bukkit.configuration.file.YamlConfiguration;
|
|
import org.eclipse.jdt.annotation.NonNull;
|
|
|
|
import com.google.common.base.Charsets;
|
|
|
|
import world.bentobox.bentobox.BentoBox;
|
|
import world.bentobox.bentobox.database.DatabaseConnector;
|
|
|
|
public class YamlDatabaseConnector implements DatabaseConnector {
|
|
|
|
private static final int MAX_LOOPS = 100;
|
|
private static final String DATABASE_FOLDER_NAME = "database";
|
|
private static final String YML = ".yml";
|
|
private final BentoBox plugin;
|
|
private final File dataFolder;
|
|
|
|
YamlDatabaseConnector(BentoBox plugin) {
|
|
this.plugin = plugin;
|
|
dataFolder = new File(plugin.getDataFolder(), DATABASE_FOLDER_NAME);
|
|
}
|
|
|
|
@Override
|
|
public String getConnectionUrl() {
|
|
return null; // Not used
|
|
}
|
|
|
|
public YamlConfiguration loadYamlFile(String tableName, String fileName) {
|
|
if (!fileName.endsWith(YML)) {
|
|
fileName = fileName + YML;
|
|
}
|
|
File yamlFile = new File(plugin.getDataFolder(), tableName + File.separator + fileName);
|
|
|
|
YamlConfiguration config = null;
|
|
if (yamlFile.exists()) {
|
|
try {
|
|
config = new YamlConfiguration();
|
|
config.load(yamlFile);
|
|
} catch (Exception e) {
|
|
/*
|
|
* TODO: Temporary fix for removing UUID tags. Remove in a few versions
|
|
*/
|
|
if (e.getMessage().contains("!!java.util.UUID")) {
|
|
removeStringFromFile(yamlFile);
|
|
// Try again
|
|
try {
|
|
Objects.requireNonNull(config).load(yamlFile);
|
|
} catch (IOException | InvalidConfigurationException e1) {
|
|
plugin.logError("Could not load yml file from database " + tableName + " " + fileName + " " + e.getMessage());
|
|
}
|
|
} else {
|
|
plugin.logError("Could not load yml file from database " + tableName + " " + fileName + " " + e.getMessage());
|
|
}
|
|
}
|
|
} else {
|
|
// Create the missing file
|
|
config = new YamlConfiguration();
|
|
plugin.log("No " + fileName + " found. Creating it...");
|
|
try {
|
|
if (plugin.getResource(fileName) != null) {
|
|
plugin.log("Using default found in jar file.");
|
|
plugin.saveResource(fileName, false);
|
|
config = new YamlConfiguration();
|
|
config.load(yamlFile);
|
|
} else {
|
|
config.save(yamlFile);
|
|
}
|
|
} catch (Exception e) {
|
|
plugin.logError("Could not create the " + fileName + " file!");
|
|
}
|
|
}
|
|
return config;
|
|
}
|
|
|
|
private void removeStringFromFile(File yamlFile) {
|
|
PrintWriter writer = null;
|
|
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(yamlFile), StandardCharsets.UTF_8))){
|
|
File temp = File.createTempFile("file", ".tmp", yamlFile.getParentFile());
|
|
writer = new PrintWriter(new OutputStreamWriter(new FileOutputStream(temp), StandardCharsets.UTF_8));
|
|
for (String line; (line = reader.readLine()) != null;) {
|
|
line = line.replace("!!java.util.UUID", "");
|
|
writer.println(line);
|
|
}
|
|
if (yamlFile.delete() && !temp.renameTo(yamlFile)) {
|
|
plugin.logError("Could not rename fixed Island object. Are the writing permissions correctly setup?");
|
|
}
|
|
} catch (Exception e) {
|
|
plugin.logError("Could not fix Island object - skipping - " + e.getMessage());
|
|
} finally {
|
|
if (writer != null) {
|
|
writer.close();
|
|
}
|
|
}
|
|
}
|
|
|
|
boolean saveYamlFile(String data, String tableName, String fileName, Map<String, String> commentMap) {
|
|
String name = fileName.endsWith(YML) ? fileName : fileName + YML;
|
|
File tableFolder = new File(plugin.getDataFolder(), tableName);
|
|
File file = new File(tableFolder, name);
|
|
if (!tableFolder.exists()) {
|
|
tableFolder.mkdirs();
|
|
}
|
|
try (Writer writer = new OutputStreamWriter(new FileOutputStream(file), Charsets.UTF_8)) {
|
|
writer.write(data);
|
|
} catch (IOException e) {
|
|
plugin.logError("Could not save yml file: " + tableName + " " + fileName + " " + e.getMessage());
|
|
return false;
|
|
}
|
|
if (commentMap != null && !commentMap.isEmpty()) {
|
|
commentFile(new File(tableFolder, name), commentMap);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Adds comments to a YAML file
|
|
* @param file - file
|
|
* @param commentMap - map of comments to apply to file
|
|
*/
|
|
private void commentFile(File file, Map<String, String> commentMap) {
|
|
// Run through the file and add in the comments
|
|
File commentedFile = new File(file.getPath() + ".tmp");
|
|
List<String> newFile = new ArrayList<>();
|
|
try (Scanner scanner = new Scanner(file, StandardCharsets.UTF_8)) {
|
|
while (scanner.hasNextLine()) {
|
|
String nextLine = scanner.nextLine();
|
|
// See if there are any comments in this line
|
|
for (Entry<String, String> e : commentMap.entrySet()) {
|
|
if (nextLine.contains(e.getKey())) {
|
|
// We want the comment to start at the same level as the entry
|
|
nextLine = " ".repeat(Math.max(0, nextLine.indexOf(e.getKey()))) +
|
|
e.getValue();
|
|
break;
|
|
}
|
|
}
|
|
newFile.add(nextLine);
|
|
}
|
|
Files.write(commentedFile.toPath(), (Iterable<String>)newFile.stream()::iterator);
|
|
copyFileUsingStream(commentedFile, file);
|
|
Files.delete(commentedFile.toPath());
|
|
} catch (IOException e1) {
|
|
plugin.logError("Could not comment config file " + file.getName() + " " + e1.getMessage());
|
|
plugin.logStacktrace(e1);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This method is necessary because Windows has problems with Files.copy and file locking.
|
|
* @param source - file
|
|
* @param dest - file
|
|
* @throws IOException - exception
|
|
*/
|
|
private void copyFileUsingStream(File source, File dest) throws IOException {
|
|
try (InputStream is = new FileInputStream(source); OutputStream os = new FileOutputStream(dest)) {
|
|
byte[] buffer = new byte[1024];
|
|
int length;
|
|
while ((length = is.read(buffer)) > 0) {
|
|
os.write(buffer, 0, length);
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
@NonNull
|
|
public String getUniqueId(String tableName) {
|
|
UUID uuid = UUID.randomUUID();
|
|
File file = new File(dataFolder, tableName + File.separator + uuid + YML);
|
|
int limit = 0;
|
|
while (file.exists() && limit++ < MAX_LOOPS) {
|
|
uuid = UUID.randomUUID();
|
|
file = new File(dataFolder, tableName + File.separator + uuid + YML);
|
|
}
|
|
return uuid.toString();
|
|
}
|
|
|
|
@Override
|
|
public boolean uniqueIdExists(String tableName, String key) {
|
|
File file = new File(dataFolder, tableName + File.separator + key + YML);
|
|
return file.exists();
|
|
}
|
|
|
|
@Override
|
|
public Object createConnection(Class<?> type) {
|
|
// Not used
|
|
return null;
|
|
}
|
|
|
|
|
|
@Override
|
|
public void closeConnection(Class<?> type) {
|
|
// not used
|
|
|
|
}
|
|
|
|
}
|