package org.openslx.dozmod;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import org.apache.log4j.Logger;
import org.openslx.dozmod.util.FormatHelper;
import org.openslx.util.QuickTimer;
import org.openslx.util.QuickTimer.Task;
/**
* Represents the configuration of the client
*
* @author Jonathan Bauer
*/
public class Config {
/**
* Logger for this class
*/
private final static Logger LOGGER = Logger.getLogger(Config.class);
public static interface ErrorCallback {
void writeError(Throwable t);
}
/**
* Out property holder with all the setting keys
*/
private static final Properties prop = new Properties();
private static ErrorCallback errorCb = null;
private static File configFile = null;
private static boolean writePending = false;
/**
* Initializes the class by determining the path
* to the config.ini on the system and setting the
* private creating the ini member from that file.
*
* This function will make a distinction between
* Linux and Windows OS's, as the standard paths
* for configuration files obviously differ.
*
* @throws IOException
*/
public static void init() throws IOException {
// Variables only needed locally
String configPath = null;
// Determine OS
String osName = System.getProperty("os.name").toLowerCase();
LOGGER.info("Machine's OS: " + osName);
if (osName.contains("windows")) {
// Windows machine. Use the environment variable 'APPDATA' which
// should point to a path similar to:
// C:\Users\<user>\AppData\Roaming
String appDataPath = System.getenv("APPDATA");
if (!appDataPath.isEmpty()) {
configPath = appDataPath;
} else {
// APPDATA was empty, let's guess
LOGGER.warn("APPDATA is empty.");
configPath = System.getProperty("user.home") + "\\AppData\\Roaming";
}
} else if (osName.contains("linux")) {
configPath = System.getProperty("user.home") + "/.config";
}
if (configPath == null || configPath.isEmpty()) {
// Not Windows nor Linux, try fallback to relative path
// TODO MacOS Support?
configPath = ".";
}
// Check if we got a path
configFile = new File(configPath + File.separatorChar + "bwSuite" + File.separatorChar + "config.properties");
// Check if the directory exists.
if (!configFile.getParentFile().exists()) {
LOGGER.info("Folder " + configFile.getParentFile() + " does not exist, creating it.");
// Does not, create it
if (!configFile.getParentFile().mkdirs()) {
throw new IOException("Could not create '" + configFile.getParentFile() + "'.");
}
}
if (!configFile.exists()) {
forceSaveInternal();
}
// Make sure all settings are saved when we exit
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
Config.forceSave();
}
});
// Load configuration from java properties file
InputStream in = new FileInputStream(configFile);
try {
prop.load(in);
} finally {
in.close();
}
}
private static void forceSaveInternal() throws FileNotFoundException, IOException {
synchronized (prop) {
prop.store(new FileOutputStream(configFile), "bwLehrpool Dozentenmodul Client Config");
}
}
public static boolean forceSave() {
synchronized (prop) {
if (!writePending)
return true;
writePending = false;
if (configFile == null)
return false;
try {
forceSaveInternal();
return true;
} catch (Exception e) {
if (errorCb != null)
errorCb.writeError(e);
}
return false;
}
}
/**
* Called internally by all set[TYPE]() methods. This triggers
* a save-task in one second, if one isn't pending yet. This is so
* we don't write the file many times, possibly concurrently, if lots
* of settings are changed.
*/
private static void queueSave() {
synchronized (prop) {
if (writePending)
return;
writePending = true;
QuickTimer.scheduleOnce(new Task() {
@Override
public void fire() {
forceSave();
}
}, 1000);
}
}
public static void setErrorCallback(ErrorCallback cb) {
errorCb = cb;
}
/**
* Query the path of the configuration file
*
* @return path to the configuration file
*/
public static String getPath() {
return configFile.getParent();
}
/*
* Getters and setters for the various config options
*/
/**
* Query the value of 'BillOfRights' from the configuration file.
*
* @return true if the user already accepted bill of rights, false
* otherwise.
*/
public static int getDisclaimerAgreement() {
return getInteger("disclaimer.accepted_version", 0);
}
/**
* Sets the value of 'BillOfRights' in the configuration file to 'value'
*
* @return true if it succeeded, false otherwise
*/
public static void setDisclaimerAgreement(int value) {
setInteger("disclaimer.accepted_version", value);
}
public static boolean getVirtualizerRead() {
return getBoolean("notice.virtualizer", false);
}
public static void setVirtualizerRead(boolean selection) {
setBoolean("notice.virtualizer", selection);
}
/**
* Get the remembered user, if set.
*
* @return user name if saved, an empty string otherwise.
*/
public static String getUsername() {
return getString("login.name", "");
}
/**
* Sets the name of the remembered user
*
* @return true if it succeeded, false otherwise
*/
public static void setUsername(String value) {
setString("login.name", value);
}
/**
* Query the value of 'Letzter Downloadpfad' from the configuration file.
*
* @return last download path if saved, the path to the user's home
* otherwise.
*/
public static String getDownloadPath() {
return getString("download.path", System.getProperty("user.home"));
}
/**
* Sets the value of 'Letzter Downloadpfad' in the configuration file to
* 'value'
*
* @return true if it succeeded, false otherwise
*/
public static void setDownloadPath(String value) {
setString("download.path", value);
}
/**
* Query the value of 'Letzter Uploadpfad' from the configuration file.
*
* @return last upload path if saved, the path to the user's home otherwise.
*/
public static String getUploadPath() {
return getString("upload.path", System.getProperty("user.home"));
}
/**
* Sets the value of "Letzter Uploadpfad" in the configuration file to
* 'value'
*
* @return true if it succeeded, false otherwise
*/
public static void setUploadPath(String value) {
setString("upload.path", value);
}
/**
* Query the IdP of the configuration file
*
* @return stored IdP
*/
public static String getIdentityProvider() {
return getString("login.idp", "");
}
/**
* Sets the value of "IdP" in the configuration file to 'value'
*
* @return true if it succeeded, false otherwise
*/
public static void setIdentityProvider(String value) {
setString("login.idp", value);
}
/**
* Query the authentication method of the configuration file
*
* @return stored IdP
*/
public static String getAuthenticationMethod() {
return getString("login.method", "ECP");
}
/**
* Sets the value of the selected authentication method in the configuration
* file to 'value'
*
* @return true if it succeeded, false otherwise
*/
public static void setAuthenticationMethod(String value) {
setString("login.method", value);
}
/*
* Generic helpers for different data types
*/
/**
* Gets the boolean from the given key.
* If nothing is found, return the given default value
*
* @param key key to query in that section
* @param defaultValue default value to be returned, if none is found.
* @return
*/
private static boolean getBoolean(String key, boolean defaultValue) {
return Boolean.parseBoolean(prop.getProperty(key, Boolean.toString(defaultValue)));
}
/**
* Sets the given key to value.
*
* @param key key to set
* @param value value to assign to key
*/
private static void setBoolean(String key, boolean value) {
prop.setProperty(key, Boolean.toString(value));
queueSave();
}
/**
* Gets the integer from the given key.
* If nothing is found, return the given default value
*
* @param key key to query in that section
* @param defaultValue default value to be returned, if none is found.
* @return
*/
private static int getInteger(String key, int defaultValue) {
return FormatHelper.parseInt(prop.getProperty(key), defaultValue);
}
/**
* Sets the given key to value.
*
* @param key key to set
* @param value value to assign to key
*/
private static void setInteger(String key, int value) {
prop.setProperty(key, Integer.toString(value));
queueSave();
}
/**
* Gets the string from the given key.
* If nothing is found, return the given default value
*
* @param key key to lookup in the section
* @param defaultValue default value to return if none is found in the file
* @return
*/
private static String getString(String key, String defaultValue) {
return prop.getProperty(key, defaultValue);
}
/**
* Sets the given 'key' in the given 'section' to 'value'.
* Restricted to string.
*
* @param key key to set
* @param value value to assign to key
*/
private static void setString(String key, String value) {
prop.setProperty(key, value);
queueSave();
}
}