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.OsHelper;
import org.openslx.util.QuickTimer;
import org.openslx.util.QuickTimer.Task;
import org.openslx.util.Util;
/**
* 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 final int TRANSFER_TIMEOUT = 20 * 1000; // 20s timeout for hung transfers
public static interface ErrorCallback {
void writeError(Throwable t);
}
/**
* Constants for font scaling boundaries
*/
public static final int FONT_SCALING_MIN = 75;
public static final int FONT_SCALING_MAX = 175;
/**
* 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 (OsHelper.isWindows()) {
// 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 (OsHelper.isLinux()) {
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 + Branding.getConfigDirectory() + File.separatorChar
+ "config.properties").getAbsoluteFile();
// 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),
Branding.getServiceName() + " 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
*/
/**
* Returns the value of 'disclaimer.accepted_version'
*
* @return version of the disclaimer the user accepted, 0 otherwise.
*/
public static String getDisclaimerAgreement() {
return getString("disclaimer.accepted_version", "");
}
/**
* Sets the value of 'disclaimer.accepted_version' to the given value
*
* @return true if it succeeded, false otherwise
*/
public static void setDisclaimerAgreement(String value) {
setString("disclaimer.accepted_version", value);
}
/**
* Returns the value of 'privacy.accepted_version'
*
* @return version of the privacy notice the user accepted, 0 otherwise.
*/
public static String getPrivacyAgreement() {
return getString("privacy.accepted_version", "");
}
/**
* Sets the value of 'privacy.accepted_version' to the given value
*
* @return true if it succeeded, false otherwise
*/
public static void setPrivacyAgreement(String value) {
setString("privacy.accepted_version", value);
}
/**
* Returns the value of 'notice.virtualizer'
*
* @return value of 'notice.virtualizer' if set, false otherwise
*/
public static boolean getVirtualizerRead() {
return getBoolean("notice.virtualizer", false);
}
/**
* Sets 'notice.virtualizer' to the given selection
*
* @param selection boolean to set the value to
*/
public static void setVirtualizerRead(boolean selection) {
setBoolean("notice.virtualizer", selection);
}
/**
* Gets the remembered user saved as 'login.name', 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 'download.path' 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 'download.path' in the configuration file to
* 'value'
*
* @return true if it succeeded, false otherwise
*/
public static void setDownloadPath(String value) {
setString("download.path", value);
}
/**
* Gets the value of 'upload.path'
*
* @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 "upload.path" the given 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);
}
/**
* Saves the current session, identified by the satellite server's address
* and token.
*
* @param satAddress
* @param satToken
*/
public static void saveCurrentSession(String satAddress, String satToken, String masterToken) {
setString("session.address", satAddress);
setString("session.token", satToken);
setString("session.mastertoken", masterToken);
}
/**
* Load a saved session
*
* @return Saved session, or <code>null</code> if no session was saved
*/
public static SavedSession getSavedSession() {
SavedSession session = new SavedSession(getString("session.address", ""),
getString("session.token", ""), getString("session.mastertoken", ""));
if (session.token.isEmpty() || session.address.isEmpty() || session.masterToken.isEmpty())
return null;
return session;
}
/**
* Set satellite used last time.
*/
public static void setLastSatellite(String value) {
setString("session.last-satellite", value);
}
/**
* Get satellite last used.
*/
public static String getLastSatellite() {
return getString("session.last-satellite", "");
}
/**
* Sets the scaling for font rendering (in percent, 100% = no scaling)
*
* @param percent to set the font scaling to
*/
public static void setFontScaling(int percent) {
setInteger("gui.fontscaling", percent);
}
/**
* Get scaling for font rendering (in percent, 100% = no scaling)
* If the saved value is not within the declared boundary, it will be
* reseted to 100.
*
* @return the saved value of 'gui.fontscaling' if within boundaries, 100
* otherwise
*/
public static int getFontScaling() {
int savedFontScaling = getInteger("gui.fontscaling", 100);
if (savedFontScaling < FONT_SCALING_MIN || savedFontScaling > FONT_SCALING_MAX) {
setFontScaling(100);
return 100;
}
return savedFontScaling;
}
/**
* Set number of connections to establish per transfer
*/
public static void setTransferConnectionCount(int count) {
setInteger("transfer.connections-per-transfer", count);
}
/**
* Get number of connections to establish per transfer
*/
public static int getTransferConnectionCount() {
int count = getInteger("transfer.connections-per-transfer", 1);
if (count < 1 || count > 4) {
count = 4;
}
return count;
}
/**
* Set the mode in which the proxy server is configured.
*
* @param mode
*/
public static void setProxyMode(ProxyMode mode) {
setString("proxy.mode", mode.toString());
}
/**
* Get the mode in which the proxy server is configured
*
* @return the saved proxy mode, ProxyMode.AUTO otherwise
*/
public static ProxyMode getProxyMode() {
try {
return ProxyMode.valueOf(getString("proxy.mode", ProxyMode.AUTO.toString()));
} catch (Exception e) {
return ProxyMode.AUTO;
}
}
/**
* Set the LookAndFeel which should be used
*
* @param value the classname of the LookAndFeel to be used
*/
public static void setLookAndFeel(String value) {
setString("gui.lookandfeel", value);
}
/**
* Get the LookAndFeel which the user wants to use
*
* @return the saved classname of the LookAndFeel, null otherwise
*/
public static String getLookAndFeel() {
return getString("gui.lookandfeel", null);
}
/**
* 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 Util.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();
}
/**
* Helper class to represent a saved session composed of the satellite
* adress,
* the satellite and master tokens
*/
public static class SavedSession {
public final String address;
public final String token;
public final String masterToken;
public SavedSession(String address, String token, String masterToken) {
this.address = address;
this.token = token;
this.masterToken = masterToken;
}
}
/**
* Enum representing the proxy mode
*/
public enum ProxyMode {
NONE,
AUTO,
SOCKS,
HTTP_CONNECT
}
}