/* * This file is part of the aidGer project. * * Copyright (C) 2010-2013 The aidGer Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package de.aidger.model; import static de.aidger.utils.Translation._; import java.io.File; import java.net.URI; import java.text.MessageFormat; import java.util.List; import java.util.Locale; import java.util.Properties; import de.aidger.model.models.*; import de.aidger.utils.*; import de.aidger.view.UI; import siena.PersistenceManagerFactory; import siena.SienaException; import siena.jdbc.JdbcPersistenceManager; import siena.jdbc.ThreadedConnectionManager; /** * Initializes Configuration and Translation and relays the methods * * @author aidGer Team */ public final class Runtime { /** * Holds he only instance of the class. */ private static Runtime instance = null; /** * True, if this is a test run. */ private boolean testRun = false; /** * The path the config is saved in. */ private String configPath; /** * The configuration class handling the settings. */ private Configuration configuration = null; /** * The class handling the translation of strings. */ private Translation translation = null; /** * The Siena Connection Manager. Only use if direct access is really needed. */ private ThreadedConnectionManager connManager = null; /** * Is this the first start of aidGer? */ private boolean firstStart = false; /** * Does the connection to the database work? */ private boolean connected = true; /** * Constructor must be private and does nothing. */ private Runtime() { } /** * Provides access to an instance of this class. * * @return Instance of the Runtime class */ public synchronized static Runtime getInstance() { if (instance == null) { instance = new Runtime(); } return instance; } /** * Resolves the OS of the user and the file path to the aidGer settings. */ public void initialize() { /* Get the path to the users home or config directory */ String home = ""; String os = System.getProperty("os.name").toLowerCase(); if (os.indexOf("linux") > -1 || os.indexOf("mac") > -1) { /* * Try using the XDG_CONFIG_DIR variable first. Provides the * standard directory according to the desktop guidelines or a user * set equivalent */ String confdir = System.getenv("XDG_CONFIG_HOME"); if (confdir == null || confdir.isEmpty()) { /* * Otherwise just use the homedir and the hidden config * directory */ confdir = System.getProperty("user.home", "."); confdir += "/.config/"; } home = confdir; } else if (os.indexOf("windows") > -1) { /* * Try using the APPDATA variable first. Should return the * ApplicationData folder but may fail on older Windows versions. */ String confdir = System.getenv("APPDATA"); if (confdir == null || confdir.isEmpty()) { /* Otherwise just use the homedir */ confdir = System.getProperty("user.home", "."); } home = confdir; } else { home = System.getProperty("user.home", "."); } configPath = home + "/aidGer/"; File file = new File(configPath); if (!file.exists() || !file.isDirectory()) { firstStart = true; /* Create the aidGer configuration directory. */ if (!file.mkdirs()) { UI.displayError(MessageFormat.format("Could not create directory \"{0}\".\n" + "Please make sure that you have enough rights to create this directory.", new Object[] { file.getPath() })); System.exit(-1); } } String templatePath = configPath + "/templates/"; File templates = new File(templatePath); if (!templates.exists() || !templates.isDirectory()) { if (!templates.mkdir()) { UI.displayError(MessageFormat.format("Could not create directory \"{0}\".\n" + "Please make sure that you have enough rights to create this directory.", new Object[] { templates.getPath() })); } } /* * Check for an environment variable AIDGER_TEST and set the config path * to "." if it is set. This is used, to seperate test and run * configurations. */ if (System.getenv("AIDGER_TEST") != null) { testRun = true; configPath = "./"; } configuration = new Configuration(); /* Use the detected language on first start */ if (firstStart || configuration.get("language") == null || configuration.get("language").isEmpty()) { /* Get the default language code and use it */ Locale loc = Locale.getDefault(); String language = loc.getLanguage(); if (language.isEmpty()) { configuration.set("language", "en"); } else { configuration.set("language", language); } } /* Check if the translation is really available and fall back to default */ String language = configuration.get("language"); boolean langFound = false; for (Pair<String, String> pair : Translation.getLanguages()) { if (pair.fst().equals(language)) { langFound = true; break; } } if (langFound) { translation = new Translation(language); } else { configuration.set("language", "en"); translation = new Translation("en"); } /* Check if an instance of aidGer is already running */ if (!testRun && !checkLock()) { UI.displayError(_("Only one instance of aidGer can be run at a time.")); System.exit(-1); } /* Set database connection settings and try to get a connection */ try { reloadDatabaseConnection(); } catch (Exception e) { Logger.error("Could not connect to the Database: " + e.toString()); e.printStackTrace(); } } /** * Get the path the config is saved in. * * @return The path of the config dir */ public String getConfigPath() { return configPath; } /** * Set a custom config path (Only to be used in tests). * * @param path * The new config path */ public void setConfigPath(String path) { configPath = path; } /** * Is this the first start of aidGer? * * @return True, if this is the first start */ public boolean isFirstStart() { return firstStart; } /** * Is this a test run of aidGer? * * @return True, if this is a test run */ public boolean isTestRun() { return testRun; } /** * Does the connection to the database work * * @return True, if it does work */ public boolean isConnected() { return connected; } /** * Returns the Siena Connection Manager. Only use if really necessary. * * @return The connection manager */ public ThreadedConnectionManager getConnectionManager() { return connManager; } /** * Reloads the database connection details from the config file * * @throws URISyntaxException and SienaException */ public void reloadDatabaseConnection() throws Exception { Properties p = new Properties(); p.put("driver", getOption("database-driver", "com.mysql.jdbc.Driver")); URI uri = new URI(getOption("database-uri", "jdbc:mysql://localhost/aidger?user=root&password=")); if (uri.getQuery() != null) { String[] user = uri.getQuery().split("&"); p.put("user", user[0].substring(5)); p.put("password", user[1].substring(9)); } p.put("url", getOption("database-uri")); connManager = new ThreadedConnectionManager(); connManager.init(p); JdbcPersistenceManager pm = new JdbcPersistenceManager(); pm.setConnectionManager(connManager); PersistenceManagerFactory.install(pm, Activity.class); /* Check if the connection was successful */ connected = true; try { connManager.getConnection(); } catch (SienaException ex) { connected = false; throw ex; } } /** * Returns the location and name of the .jar file. * * @return The location */ public String getJarLocation() { String location = getClass().getProtectionDomain().getCodeSource().getLocation().toString(); int idx = location.indexOf(":"); /* Windows uses file:/C:/folder whereas Unix uses file:/folder */ if (idx != location.lastIndexOf(":")) { location = location.substring(idx + 2); } else { location = location.substring(idx + 1); } return location; } /** * Get the value of an option. * * @param option * The option to get * @return The value of the specified option */ public String getOption(String option) { return configuration.get(option); } /** * Get the value of an option or the default if the option doesn't exist * * @param option * The option to get * @param def * The default value * @return The value of the specified option or the default value */ public String getOption(String option, String def) { String ret = configuration.get(option); if (ret == null) { configuration.set(option, def); return def; } return ret; } /** * Get an array of values for the specified option * * @param option * The option to get * @return Array containing all values */ public String[] getOptionArray(String option) { String str = getOption(option); if (str == null || (!str.startsWith("[") || !str.endsWith("]"))) { return null; } return str.substring(1, str.length() - 1).split(", "); } /** * Set the value of an option. * * @param option * The option to set * @param value * The value to set it to */ public void setOption(String option, String value) { configuration.set(option, value); } /** * Sets the value of a property by converting an array into a single string. * * @param option * The property to change * @param values * Array of all values */ public void setOptionArray(String option, String[] values) { setOption(option, java.util.Arrays.toString(values)); } /** * Remove an option from the config. * * @param option * The option to remove */ public void clearOption(String option) { configuration.remove(option); } /** * Get a list of all languages installed on the system. The format is 0 => * short, 1 => long language name. * * @return The list of all installed languages */ public List<Pair<String, String>> getLanguages() { return translation.getLanguages(); } /** * Check for a lock file or create it to only allow one running instance. * * @return True if no lock file exists and the application can be started */ protected boolean checkLock() { try { final File file = new File(configPath + "/aidger.lock"); final java.io.RandomAccessFile randomAccessFile = new java.io.RandomAccessFile( file, "rw"); final java.nio.channels.FileLock fileLock = randomAccessFile .getChannel().tryLock(); if (fileLock != null) { java.lang.Runtime.getRuntime().addShutdownHook(new Thread() { @Override public void run() { try { fileLock.release(); randomAccessFile.close(); file.delete(); } catch (Exception e) { System.err.println("Unable to remove lock file"); } } }); return true; } } catch (Exception e) { System.err.println("Unable to create and/or lock file"); } return false; } }