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\\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 null 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 } }