274 lines
9.3 KiB
Java
Raw Normal View History

2015-07-05 20:51:34 +10:00
package com.intellectualcrafters.configuration.file;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
2015-07-06 01:44:10 +10:00
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
2015-07-05 20:51:34 +10:00
import java.util.Map;
2015-07-31 00:25:16 +10:00
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.error.YAMLException;
import org.yaml.snakeyaml.representer.Representer;
import com.intellectualcrafters.configuration.Configuration;
import com.intellectualcrafters.configuration.ConfigurationSection;
import com.intellectualcrafters.configuration.InvalidConfigurationException;
import com.intellectualcrafters.plot.PS;
2015-07-05 20:51:34 +10:00
/**
* An implementation of {@link Configuration} which saves all files in Yaml.
* Note that this implementation is not synchronized.
*/
2015-09-13 14:04:31 +10:00
public class YamlConfiguration extends FileConfiguration {
2015-07-05 20:51:34 +10:00
protected static final String COMMENT_PREFIX = "# ";
protected static final String BLANK_CONFIG = "{}\n";
private final DumperOptions yamlOptions = new DumperOptions();
private final Representer yamlRepresenter = new YamlRepresenter();
private final Yaml yaml = new Yaml(new YamlConstructor(), yamlRepresenter, yamlOptions);
2015-09-13 14:04:31 +10:00
2015-07-05 20:51:34 +10:00
@Override
2016-01-20 12:40:04 +01:00
@SuppressWarnings("deprecation")
2015-09-13 14:04:31 +10:00
public String saveToString() {
2015-07-05 20:51:34 +10:00
yamlOptions.setIndent(options().indent());
yamlOptions.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
yamlOptions.setAllowUnicode(SYSTEM_UTF);
yamlRepresenter.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
2015-09-13 14:04:31 +10:00
2015-09-11 20:09:22 +10:00
final String header = buildHeader();
2015-07-05 20:51:34 +10:00
String dump = yaml.dump(getValues(false));
2015-09-13 14:04:31 +10:00
if (dump.equals(BLANK_CONFIG)) {
2015-07-05 20:51:34 +10:00
dump = "";
}
2015-09-13 14:04:31 +10:00
2015-07-05 20:51:34 +10:00
return header + dump;
}
2015-09-13 14:04:31 +10:00
2015-07-05 20:51:34 +10:00
@Override
2015-09-13 14:04:31 +10:00
public void loadFromString(final String contents) throws InvalidConfigurationException {
if (contents == null) {
throw new NullPointerException("Contents cannot be null");
}
2015-07-05 20:51:34 +10:00
Map<?, ?> input;
2015-09-13 14:04:31 +10:00
try {
2015-07-05 20:51:34 +10:00
input = (Map<?, ?>) yaml.load(contents);
2015-09-13 14:04:31 +10:00
} catch (final YAMLException e) {
2015-07-05 20:51:34 +10:00
throw new InvalidConfigurationException(e);
2015-09-13 14:04:31 +10:00
} catch (final ClassCastException e) {
2015-07-05 20:51:34 +10:00
throw new InvalidConfigurationException("Top level is not a Map.");
}
2015-09-13 14:04:31 +10:00
2015-09-11 20:09:22 +10:00
final String header = parseHeader(contents);
2015-09-13 14:04:31 +10:00
if (header.length() > 0) {
2015-07-05 20:51:34 +10:00
options().header(header);
}
2015-09-13 14:04:31 +10:00
if (input != null) {
2015-07-05 20:51:34 +10:00
convertMapsToSections(input, this);
}
}
2015-09-13 14:04:31 +10:00
protected void convertMapsToSections(final Map<?, ?> input, final ConfigurationSection section) {
for (final Map.Entry<?, ?> entry : input.entrySet()) {
2015-09-11 20:09:22 +10:00
final String key = entry.getKey().toString();
final Object value = entry.getValue();
2015-09-13 14:04:31 +10:00
if (value instanceof Map) {
2015-07-05 20:51:34 +10:00
convertMapsToSections((Map<?, ?>) value, section.createSection(key));
2015-09-13 14:04:31 +10:00
} else {
2015-07-05 20:51:34 +10:00
section.set(key, value);
}
}
}
2015-09-13 14:04:31 +10:00
protected String parseHeader(final String input) {
2015-09-11 20:09:22 +10:00
final String[] lines = input.split("\r?\n", -1);
final StringBuilder result = new StringBuilder();
2015-07-05 20:51:34 +10:00
boolean readingHeader = true;
boolean foundHeader = false;
2015-09-13 14:04:31 +10:00
for (int i = 0; (i < lines.length) && (readingHeader); i++) {
2015-09-11 20:09:22 +10:00
final String line = lines[i];
2015-09-13 14:04:31 +10:00
if (line.startsWith(COMMENT_PREFIX)) {
if (i > 0) {
2015-07-05 20:51:34 +10:00
result.append("\n");
}
2015-09-13 14:04:31 +10:00
if (line.length() > COMMENT_PREFIX.length()) {
2015-07-05 20:51:34 +10:00
result.append(line.substring(COMMENT_PREFIX.length()));
}
2015-09-13 14:04:31 +10:00
2015-07-05 20:51:34 +10:00
foundHeader = true;
2015-09-13 14:04:31 +10:00
} else if ((foundHeader) && (line.length() == 0)) {
2015-07-05 20:51:34 +10:00
result.append("\n");
2015-09-13 14:04:31 +10:00
} else if (foundHeader) {
2015-07-05 20:51:34 +10:00
readingHeader = false;
}
}
2015-09-13 14:04:31 +10:00
2015-07-05 20:51:34 +10:00
return result.toString();
}
2015-09-13 14:04:31 +10:00
2015-07-05 20:51:34 +10:00
@Override
2015-09-13 14:04:31 +10:00
protected String buildHeader() {
2015-09-11 20:09:22 +10:00
final String header = options().header();
2015-09-13 14:04:31 +10:00
if (options().copyHeader()) {
2015-09-11 20:09:22 +10:00
final Configuration def = getDefaults();
2015-09-13 14:04:31 +10:00
if ((def != null) && (def instanceof FileConfiguration)) {
2015-09-11 20:09:22 +10:00
final FileConfiguration filedefaults = (FileConfiguration) def;
final String defaultsHeader = filedefaults.buildHeader();
2015-09-13 14:04:31 +10:00
if ((defaultsHeader != null) && (defaultsHeader.length() > 0)) {
return defaultsHeader;
}
2015-07-05 20:51:34 +10:00
}
}
2015-09-13 14:04:31 +10:00
if (header == null) {
return "";
}
2015-09-11 20:09:22 +10:00
final StringBuilder builder = new StringBuilder();
final String[] lines = header.split("\r?\n", -1);
2015-07-05 20:51:34 +10:00
boolean startedHeader = false;
2015-09-13 14:04:31 +10:00
for (int i = lines.length - 1; i >= 0; i--) {
2015-07-05 20:51:34 +10:00
builder.insert(0, "\n");
2015-09-13 14:04:31 +10:00
if ((startedHeader) || (lines[i].length() != 0)) {
2015-07-05 20:51:34 +10:00
builder.insert(0, lines[i]);
builder.insert(0, COMMENT_PREFIX);
startedHeader = true;
}
}
2015-09-13 14:04:31 +10:00
2015-07-05 20:51:34 +10:00
return builder.toString();
}
2015-09-13 14:04:31 +10:00
2015-07-05 20:51:34 +10:00
@Override
2015-09-13 14:04:31 +10:00
public YamlConfigurationOptions options() {
if (options == null) {
2015-07-05 20:51:34 +10:00
options = new YamlConfigurationOptions(this);
}
2015-09-13 14:04:31 +10:00
2015-07-05 20:51:34 +10:00
return (YamlConfigurationOptions) options;
}
2015-09-13 14:04:31 +10:00
2015-07-05 20:51:34 +10:00
/**
* Creates a new {@link YamlConfiguration}, loading from the given file.
* <p>
* Any errors loading the Configuration will be logged and then ignored.
* If the specified input is not a valid config, a blank config will be
* returned.
* <p>
* The encoding used may follow the system dependent default.
*
* @param file Input file
* @return Resulting configuration
* @throws IllegalArgumentException Thrown if file is null
*/
2015-09-13 14:04:31 +10:00
public static YamlConfiguration loadConfiguration(final File file) {
if (file == null) {
throw new NullPointerException("File cannot be null");
}
2015-09-11 20:09:22 +10:00
final YamlConfiguration config = new YamlConfiguration();
2015-09-13 14:04:31 +10:00
try {
2015-07-05 20:51:34 +10:00
config.load(file);
2015-09-13 14:04:31 +10:00
} catch (final Exception ex) {
try {
2015-09-11 20:09:22 +10:00
file.getAbsolutePath();
2015-07-06 01:44:10 +10:00
File dest = new File(file.getAbsolutePath() + "_broken");
int i = 0;
2015-09-13 14:04:31 +10:00
while (dest.exists()) {
2015-07-06 01:44:10 +10:00
dest = new File(file.getAbsolutePath() + "_broken_" + i++);
}
2015-09-11 20:09:22 +10:00
Files.copy(file.toPath(), dest.toPath(), StandardCopyOption.REPLACE_EXISTING);
2015-07-31 00:25:16 +10:00
PS.debug("&dCould not read: &7" + file);
2016-02-04 18:45:50 -05:00
PS.debug("&dRenamed to: &7" + dest.getName());
2015-07-31 00:25:16 +10:00
PS.debug("&c============ Full stacktrace ============");
2015-07-06 01:44:10 +10:00
ex.printStackTrace();
2015-07-31 00:25:16 +10:00
PS.debug("&c=========================================");
2015-09-13 14:04:31 +10:00
} catch (final IOException e) {
2015-07-06 01:44:10 +10:00
e.printStackTrace();
}
2015-07-05 20:51:34 +10:00
}
2015-09-13 14:04:31 +10:00
2015-07-05 20:51:34 +10:00
return config;
}
2015-09-13 14:04:31 +10:00
2015-07-05 20:51:34 +10:00
/**
* Creates a new {@link YamlConfiguration}, loading from the given stream.
* <p>
* Any errors loading the Configuration will be logged and then ignored.
* If the specified input is not a valid config, a blank config will be
* returned.
*
* @param stream Input stream
* @return Resulting configuration
* @throws IllegalArgumentException Thrown if stream is null
* @deprecated does not properly consider encoding
* @see #load(InputStream)
* @see #loadConfiguration(Reader)
*/
@Deprecated
2015-09-13 14:04:31 +10:00
public static YamlConfiguration loadConfiguration(final InputStream stream) {
if (stream == null) {
throw new NullPointerException("Stream cannot be null");
}
2015-09-11 20:09:22 +10:00
final YamlConfiguration config = new YamlConfiguration();
2015-09-13 14:04:31 +10:00
try {
2015-07-05 20:51:34 +10:00
config.load(stream);
2015-09-13 14:04:31 +10:00
} catch (final IOException ex) {
2015-07-31 00:25:16 +10:00
PS.debug("Cannot load configuration from stream");
2015-07-05 20:51:34 +10:00
ex.printStackTrace();
2015-09-13 14:04:31 +10:00
} catch (final InvalidConfigurationException ex) {
2015-07-05 20:51:34 +10:00
ex.printStackTrace();
2015-07-31 00:25:16 +10:00
PS.debug("Cannot load configuration from stream");
2015-07-05 20:51:34 +10:00
}
2015-09-13 14:04:31 +10:00
2015-07-05 20:51:34 +10:00
return config;
}
2015-09-13 14:04:31 +10:00
2015-07-05 20:51:34 +10:00
/**
* Creates a new {@link YamlConfiguration}, loading from the given reader.
* <p>
* Any errors loading the Configuration will be logged and then ignored.
* If the specified input is not a valid config, a blank config will be
* returned.
*
* @param reader input
* @return resulting configuration
* @throws IllegalArgumentException Thrown if stream is null
*/
2015-09-13 14:04:31 +10:00
public static YamlConfiguration loadConfiguration(final Reader reader) {
if (reader == null) {
throw new NullPointerException("Reader cannot be null");
}
2015-09-11 20:09:22 +10:00
final YamlConfiguration config = new YamlConfiguration();
2015-09-13 14:04:31 +10:00
try {
2015-07-05 20:51:34 +10:00
config.load(reader);
2015-09-13 14:04:31 +10:00
} catch (final IOException ex) {
2015-07-31 00:25:16 +10:00
PS.debug("Cannot load configuration from stream");
2015-07-05 20:51:34 +10:00
ex.printStackTrace();
2015-09-13 14:04:31 +10:00
} catch (final InvalidConfigurationException ex) {
2015-07-31 00:25:16 +10:00
PS.debug("Cannot load configuration from stream");
2015-07-05 20:51:34 +10:00
ex.printStackTrace();
}
2015-09-13 14:04:31 +10:00
2015-07-05 20:51:34 +10:00
return config;
}
}