Created
January 25, 2017 14:01
-
-
Save sirolf2009/70fda7fef80f926375733d2183539d88 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.io.File; | |
import java.io.FileNotFoundException; | |
import java.io.FileOutputStream; | |
import java.io.FileReader; | |
import java.io.IOException; | |
import java.io.PrintWriter; | |
import java.lang.reflect.Field; | |
import java.util.ArrayList; | |
import java.util.HashMap; | |
import java.util.List; | |
import java.util.Map; | |
import java.util.function.Consumer; | |
import org.apache.commons.configuration2.FileBasedConfiguration; | |
import org.apache.commons.configuration2.XMLPropertiesConfiguration; | |
import org.apache.commons.configuration2.ex.ConfigurationException; | |
import org.apache.commons.lang3.tuple.ImmutablePair; | |
import org.apache.commons.lang3.tuple.ImmutableTriple; | |
import org.apache.commons.lang3.tuple.Pair; | |
import org.apache.commons.lang3.tuple.Triple; | |
/** | |
* Generic hell.... my head hurts | |
* | |
* @author Floris | |
*/ | |
public abstract class SettingsConfiguration { | |
private final Map<Class<? extends Object>, Consumer<Triple<String, Object, Pair<Consumer<Object>, Consumer<Exception>>>>> typesAndGetters = new HashMap<Class<? extends Object>, Consumer<Triple<String, Object, Pair<Consumer<Object>, Consumer<Exception>>>>>(); | |
private final File file; | |
private final FileBasedConfiguration configuration; | |
private final Map<String, Object> defaults; | |
public SettingsConfiguration(File file) throws FileNotFoundException, ConfigurationException, IOException { | |
this.file = file; | |
initializeFile(file); | |
configuration = new XMLPropertiesConfiguration(); | |
configuration.read(new FileReader(file)); | |
defaults = new HashMap<String, Object>(); | |
setupTypesAndGetters(); | |
} | |
public static void initializeFile(File file) throws IOException { | |
if(!file.exists()) { | |
file.getParentFile().mkdirs(); | |
if(file.createNewFile()) { | |
writeNewPropertiesFile(file); | |
} | |
} | |
} | |
public static void writeNewPropertiesFile(File file) throws FileNotFoundException { | |
PrintWriter writer = new PrintWriter(new FileOutputStream(file)); | |
writer.println("<?xml version=\"1.0\" ?>"); | |
writer.println("<!DOCTYPE properties SYSTEM \"http://java.sun.com/dtd/properties.dtd\" >"); | |
writer.println("<properties>"); | |
writer.println("</properties>"); | |
writer.close(); | |
} | |
public static void savePropertiesFile(File file, FileBasedConfiguration configuration) throws FileNotFoundException, ConfigurationException, IOException { | |
initializeFile(file); | |
PrintWriter writer = new PrintWriter(file); | |
configuration.write(writer); | |
writer.close(); | |
} | |
public void initializeDefaults() throws IllegalArgumentException, IllegalAccessException { | |
for(Field field : this.getClass().asSubclass(this.getClass()).getDeclaredFields()) { | |
if(field.isAnnotationPresent(Setting.class)) { | |
if(!field.isAccessible()) { | |
field.setAccessible(true); | |
} | |
defaults.put(field.getName(), field.get(this)); | |
} | |
} | |
} | |
final List<Exception> exceptions = new ArrayList<Exception>(); | |
public void reload() throws FileNotFoundException, ConfigurationException, IOException { | |
synchronized(exceptions) { | |
exceptions.clear(); | |
reload(error -> { | |
exceptions.add(error.getKey()); | |
}); | |
if(exceptions.size() > 0) { | |
Exception e = exceptions.get(0); | |
if(e instanceof FileNotFoundException) { | |
throw (FileNotFoundException) e; | |
} else if(e instanceof ConfigurationException) { | |
throw (ConfigurationException) e; | |
} else if(e instanceof IOException) { | |
throw (IOException) e; | |
} else { | |
throw new RuntimeException(e); | |
} | |
} | |
} | |
} | |
public void reload(Consumer<Pair<Exception, Field>> onError) { | |
for(final Field field : this.getClass().asSubclass(this.getClass()).getDeclaredFields()) { | |
if(field.isAnnotationPresent(Setting.class)) { | |
Class<?> type = field.getType(); | |
typesAndGetters.get(type).accept(new ImmutableTriple<String, Object, Pair<Consumer<Object>, Consumer<Exception>>>(field.getName(), (Object) defaults.get(field.getName()), new ImmutablePair<Consumer<Object>, Consumer<Exception>>(value -> { | |
try { | |
field.set(this, value); | |
} catch(IllegalArgumentException | IllegalAccessException e) { | |
onError.accept(new ImmutablePair<Exception, Field>(e, field)); | |
} | |
}, error -> onError.accept(new ImmutablePair<Exception, Field>(error, field))))); | |
} | |
} | |
} | |
public void setupTypesAndGetters() { | |
typesAndGetters.put(Boolean.class, getBoolean); | |
typesAndGetters.put(boolean.class, getBoolean); | |
typesAndGetters.put(Byte.class, getByte); | |
typesAndGetters.put(byte.class, getByte); | |
typesAndGetters.put(Double.class, getDouble); | |
typesAndGetters.put(double.class, getDouble); | |
typesAndGetters.put(Float.class, getFloat); | |
typesAndGetters.put(float.class, getFloat); | |
typesAndGetters.put(int.class, getInteger); | |
typesAndGetters.put(Integer.class, getInteger); | |
typesAndGetters.put(long.class, getLong); | |
typesAndGetters.put(Long.class, getLong); | |
typesAndGetters.put(short.class, getShort); | |
typesAndGetters.put(Short.class, getShort); | |
typesAndGetters.put(String.class, getString); | |
} | |
public Consumer<Triple<String, Object, Pair<Consumer<Object>, Consumer<Exception>>>> getBoolean = input -> { | |
try { | |
input.getRight().getLeft().accept(getProperty(input.getLeft(), (Boolean) input.getMiddle(), Boolean.class)); | |
} catch(ConfigurationException | IOException e) { | |
input.getRight().getRight().accept(e); | |
} | |
}; | |
public Consumer<Triple<String, Object, Pair<Consumer<Object>, Consumer<Exception>>>> getByte = input -> { | |
try { | |
input.getRight().getLeft().accept(getProperty(input.getLeft(), (Byte) input.getMiddle(), Byte.class)); | |
} catch(ConfigurationException | IOException e) { | |
input.getRight().getRight().accept(e); | |
} | |
}; | |
public Consumer<Triple<String, Object, Pair<Consumer<Object>, Consumer<Exception>>>> getDouble = input -> { | |
try { | |
input.getRight().getLeft().accept(getProperty(input.getLeft(), (Double) input.getMiddle(), Double.class)); | |
} catch(ConfigurationException | IOException e) { | |
input.getRight().getRight().accept(e); | |
} | |
}; | |
public Consumer<Triple<String, Object, Pair<Consumer<Object>, Consumer<Exception>>>> getFloat = input -> { | |
try { | |
input.getRight().getLeft().accept(getProperty(input.getLeft(), (Float) input.getMiddle(), Float.class)); | |
} catch(ConfigurationException | IOException e) { | |
input.getRight().getRight().accept(e); | |
} | |
}; | |
public Consumer<Triple<String, Object, Pair<Consumer<Object>, Consumer<Exception>>>> getInteger = input -> { | |
try { | |
input.getRight().getLeft().accept(getProperty(input.getLeft(), (Integer) input.getMiddle(), Integer.class)); | |
} catch(ConfigurationException | IOException e) { | |
input.getRight().getRight().accept(e); | |
} | |
}; | |
public Consumer<Triple<String, Object, Pair<Consumer<Object>, Consumer<Exception>>>> getLong = input -> { | |
try { | |
input.getRight().getLeft().accept(getProperty(input.getLeft(), (Long) input.getMiddle(), Long.class)); | |
} catch(ConfigurationException | IOException e) { | |
input.getRight().getRight().accept(e); | |
} | |
}; | |
public Consumer<Triple<String, Object, Pair<Consumer<Object>, Consumer<Exception>>>> getShort = input -> { | |
try { | |
input.getRight().getLeft().accept(getProperty(input.getLeft(), (Short) input.getMiddle(), Short.class)); | |
} catch(ConfigurationException | IOException e) { | |
input.getRight().getRight().accept(e); | |
} | |
}; | |
public Consumer<Triple<String, Object, Pair<Consumer<Object>, Consumer<Exception>>>> getString = input -> { | |
try { | |
input.getRight().getLeft().accept(getProperty(input.getLeft(), (String) input.getMiddle(), String.class)); | |
} catch(ConfigurationException | IOException e) { | |
input.getRight().getRight().accept(e); | |
} | |
}; | |
public boolean getBoolean(String key, boolean defaultValue) throws FileNotFoundException, ConfigurationException, IOException { | |
return getProperty(key, defaultValue, boolean.class); | |
} | |
public Boolean getBoolean(String key, Boolean defaultValue) throws FileNotFoundException, ConfigurationException, IOException { | |
return getProperty(key, defaultValue, Boolean.class); | |
} | |
public byte getByte(String key, byte defaultValue) throws FileNotFoundException, ConfigurationException, IOException { | |
return getProperty(key, defaultValue, byte.class); | |
} | |
public Byte getByte(String key, Byte defaultValue) throws FileNotFoundException, ConfigurationException, IOException { | |
return getProperty(key, defaultValue, Byte.class); | |
} | |
public double getDouble(String key, double defaultValue) throws FileNotFoundException, ConfigurationException, IOException { | |
return getProperty(key, defaultValue, double.class); | |
} | |
public Double getDouble(String key, Double defaultValue) throws FileNotFoundException, ConfigurationException, IOException { | |
return getProperty(key, defaultValue, Double.class); | |
} | |
public float getFloat(String key, float defaultValue) throws FileNotFoundException, ConfigurationException, IOException { | |
return getProperty(key, defaultValue, float.class); | |
} | |
public Float getFloat(String key, Float defaultValue) throws FileNotFoundException, ConfigurationException, IOException { | |
return getProperty(key, defaultValue, Float.class); | |
} | |
public int getInt(String key, int defaultValue) throws FileNotFoundException, ConfigurationException, IOException { | |
return getProperty(key, defaultValue, int.class); | |
} | |
public Integer getInteger(String key, Integer defaultValue) throws FileNotFoundException, ConfigurationException, IOException { | |
return getProperty(key, defaultValue, Integer.class); | |
} | |
public long getLong(String key, long defaultValue) throws FileNotFoundException, ConfigurationException, IOException { | |
return getProperty(key, defaultValue, long.class); | |
} | |
public Long getLong(String key, Long defaultValue) throws FileNotFoundException, ConfigurationException, IOException { | |
return getProperty(key, defaultValue, Long.class); | |
} | |
public short getShort(String key, short defaultValue) throws FileNotFoundException, ConfigurationException, IOException { | |
return getProperty(key, defaultValue, short.class); | |
} | |
public Short getShort(String key, Short defaultValue) throws FileNotFoundException, ConfigurationException, IOException { | |
return getProperty(key, defaultValue, Short.class); | |
} | |
public String getString(String key, String defaultValue) throws FileNotFoundException, ConfigurationException, IOException { | |
return getProperty(key, defaultValue, String.class); | |
} | |
private <T> T getProperty(String key, T defaultValue, Class<T> clazz) throws FileNotFoundException, ConfigurationException, IOException { | |
if(!configuration.containsKey(key)) { | |
if(defaultValue == null) { | |
throw new ConfigurationException(key+" is not defined in the settings and no default has been provided"); | |
} | |
configuration.addProperty(key, defaultValue); | |
savePropertiesFile(file, configuration); | |
return configuration.get(clazz, key, defaultValue); | |
} | |
return configuration.get(clazz, key, defaultValue); | |
} | |
public File getFile() { | |
return file; | |
} | |
public FileBasedConfiguration getConfiguration() { | |
return configuration; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment