package net.krazyweb.starmodmanager.data; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.HashSet; import java.util.Map; import java.util.Properties; import java.util.Set; import javafx.concurrent.Task; import javafx.concurrent.WorkerStateEvent; import javafx.event.EventHandler; import net.krazyweb.starmodmanager.dialogue.MessageDialogue; import net.krazyweb.starmodmanager.dialogue.MessageDialogue.MessageType; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.core.LoggerContext; public class Settings implements SettingsModelInterface { private static final Logger log = LogManager.getLogger(Settings.class); private static enum LoggerType { ALL, CONSOLE, FILE } private static final int VERSION_MAJOR = 2; private static final int VERSION_MINOR = 0; private static final int VERSION_PATCH = 2; private static final String VERSION_EXTRA = ""; private static final String APPLE = "Golden Delicious"; private static final String VERSION_STRING = VERSION_MAJOR + "." + VERSION_MINOR + "." + VERSION_PATCH + VERSION_EXTRA; private static OS operatingSystem; private static String operatingSystemName; private Map<String, String> settings; private Properties defaultProperties; private Set<Observer> observers; private DatabaseModelInterface database; private DatabaseModelFactory databaseFactory; protected Settings(final DatabaseModelFactory databaseFactory) { observers = new HashSet<>(); this.databaseFactory = databaseFactory; } /* * Sets the appropriate logging levels for the logger based on launch conditions. * If the program is launched from a .jar file, then the console logging is turned off. * Otherwise, it is left on and file logging is turned off. */ @Override public Task<Void> getInitializeLoggerTask() { final Task<Void> task = new Task<Void>() { @Override protected Void call() throws Exception { this.updateMessage("Configuring Logger"); this.updateProgress(0.0, 4.0); identifyOS(); this.updateProgress(1.0, 4.0); //Print program information before adjusting loggers. setLoggerLevel(Level.TRACE, LoggerType.ALL); this.updateProgress(2.0, 4.0); log.info("[Application Launched]"); log.info("Starbound Mod Manager - Version {}", VERSION_STRING); log.info("Running on {}", operatingSystemName); this.updateProgress(3.0, 4.0); if (Settings.class.getResource("Settings.class").toString().startsWith("jar:")) { setLoggerLevel(Level.OFF, LoggerType.CONSOLE); setLoggerLevel(Level.WARN, LoggerType.FILE); } else { setLoggerLevel(Level.TRACE, LoggerType.CONSOLE); setLoggerLevel(Level.TRACE, LoggerType.FILE); } this.updateProgress(4.0, 4.0); return null; } }; task.setOnSucceeded(new EventHandler<WorkerStateEvent>() { @Override public void handle(final WorkerStateEvent event) { notifyObservers("loggerconfigured"); } }); return task; } @Override public Task<Void> getLoadSettingsTask() { database = databaseFactory.getInstance(); final Task<Void> task = new Task<Void>() { @Override protected Void call() throws Exception { this.updateMessage("Loading Settings From Database"); this.updateProgress(0.0, 3.0); settings = database.getProperties(); this.updateProgress(1.0, 3.0); defaultProperties = new Properties(); defaultProperties.load(Settings.class.getClassLoader().getResourceAsStream("defaultsettings.properties")); this.updateProgress(2.0, 3.0); if (Settings.class.getResource("Settings.class").toString().startsWith("jar:")) { setLoggerLevel(Level.OFF, LoggerType.CONSOLE); setLoggerLevel(getPropertyLevel("loggerlevel"), LoggerType.FILE); } if (Files.notExists(getPropertyPath("modsdir"))) { Files.createDirectories(getPropertyPath("modsdir")); } this.updateProgress(3.0, 3.0); log.debug("Settings Loaded"); return null; } }; task.setOnSucceeded(new EventHandler<WorkerStateEvent>() { @Override public void handle(final WorkerStateEvent event) { notifyObservers("settingsloaded"); } }); task.setOnFailed(new EventHandler<WorkerStateEvent>() { @Override public void handle(final WorkerStateEvent event) { log.error("", task.getException()); MessageDialogue dialogue = new MessageDialogue("An error occurred while loading the settings. Please see the log for more information.", "Settings Error", MessageType.ERROR, new NotLoadedLocalizerFactory()); dialogue.getResult(); } }); return task; } private final void identifyOS() { operatingSystemName = System.getProperty("os.name").toLowerCase(); if (operatingSystemName.contains("win")) { operatingSystem = OS.WINDOWS; } else if (operatingSystemName.contains("mac")) { operatingSystem = OS.MACOS; } else if (operatingSystemName.contains("nix") || operatingSystemName.contains("nux") || operatingSystemName.contains("aix")) { if (System.getProperty("os.arch").contains("64")) { operatingSystem = OS.LINUX64; } else { operatingSystem = OS.LINUX32; } } operatingSystemName = System.getProperty("os.name"); } @Override public OS getOperatingSystem() { return operatingSystem; } @Override public void setLoggerLevel(final Level level) { if (Settings.class.getResource("Settings.class").toString().startsWith("jar:")) { setLoggerLevel(Level.OFF, LoggerType.CONSOLE); setLoggerLevel(level, LoggerType.FILE); setProperty("loggerlevel", level); } } private void setLoggerLevel(final Level level, final LoggerType loggerType) { if (loggerType == LoggerType.ALL) { System.setProperty("consolelevel", level.toString()); System.setProperty("filelevel", level.toString()); } else { if (loggerType == LoggerType.CONSOLE) { System.setProperty("consolelevel", level.toString()); } else if (loggerType == LoggerType.FILE) { System.setProperty("filelevel", level.toString()); } } LoggerContext ctx = (LoggerContext) LogManager.getContext(false); ctx.reconfigure(); } @Override public String getPropertyString(final String key) { if (settings.containsKey(key)) { return settings.get(key); } if (defaultProperties.containsKey(key)) { log.debug("Property '{}' not found in database. Using default value: '{}'", key, defaultProperties.getProperty(key)); return defaultProperties.getProperty(key); } else { log.warn("Could not find property: {}", key); return null; } } @Override public int getPropertyInt(final String key) { return Integer.parseInt(getPropertyString(key)); } @Override public double getPropertyDouble(final String key) { return Double.parseDouble(getPropertyString(key)); } @Override public boolean getPropertyBoolean(final String key) { return Boolean.parseBoolean(getPropertyString(key)); } @Override public Path getPropertyPath(final String key) { return Paths.get(getPropertyString(key)); } @Override public Level getPropertyLevel(final String key) { return Level.toLevel(getPropertyString(key)); } @Override public void setProperty(final String key, final Object property) { settings.put(key, property.toString()); notifyObservers("propertychanged:" + key); database.setProperty(key, property); log.debug("Property Changed: {} -> {}", key, property); } @Override public String getVersion() { return VERSION_STRING; } @Override public String getApple() { return APPLE; } @Override public void addObserver(final Observer observer) { observers.add(observer); } @Override public void removeObserver(final Observer observer) { observers.remove(observer); } private final void notifyObservers(final Object message) { for (final Observer o : observers) { o.update(this, message); } } }