diff --git a/.gitignore b/.gitignore index 69cb3e6..3079950 100644 --- a/.gitignore +++ b/.gitignore @@ -32,4 +32,7 @@ build/ ### VS Code ### .vscode/ **script** -*config.json \ No newline at end of file +*config.json + +### Logs ### +*.log \ No newline at end of file diff --git a/pom.xml b/pom.xml index 853f4c4..8e4cb8c 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ 4.0.0 com.smart.home file.is.my.command - 1.1-SNAPSHOT + 1.2-SNAPSHOT pc.daemon jar Daemon that will be installed on computers and will handle simple daily tasks @@ -82,5 +82,20 @@ 3.4.2 + + + + org.mockito + mockito-core + 2.23.0 + test + + + junit + junit + 4.12 + test + + diff --git a/src/main/java/com/smart/home/pc/daemon/Application.java b/src/main/java/com/smart/home/pc/daemon/Application.java index afe8399..d9a385b 100644 --- a/src/main/java/com/smart/home/pc/daemon/Application.java +++ b/src/main/java/com/smart/home/pc/daemon/Application.java @@ -2,21 +2,19 @@ import java.io.File; import java.io.IOException; -import java.io.Reader; import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.Date; import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import com.google.gson.Gson; import com.smart.home.pc.daemon.dto.Config; import com.smart.home.pc.daemon.dto.FullConfiguration; import com.smart.home.pc.daemon.impl.Daemon; +import com.smart.home.pc.daemon.service.impl.ConfigurationLoaderServiceImpl; public class Application { @@ -30,57 +28,24 @@ public static void main(String[] args) throws RuntimeException, IOException, Int // Determine local jar path Path jarAbsolutePath = FileSystems.getDefault().getPath("").toAbsolutePath(); - // Check and create configuration file if not found - String configPath = jarAbsolutePath.toString() + File.separator + CONFIGURATION_FILE_NAME; - Path configFilePath = Paths.get(configPath); - File configFile = new File(configPath); - - // Create configuration file - if (!configFile.isFile()) { - try { - configFile.createNewFile(); - } catch (IOException e) { - LOGGER.error("Could not create the configuration file: " + configFilePath.toString()); - e.printStackTrace(); - System.exit(1); - } - } - - if (configFile.isFile()) { - LOGGER.info("Configuration location: " + configPath); - } - - // create Gson instance - Gson gson = new Gson(); - Config daemonConfig = new Config(); - - // create a reader - Reader reader; - try { - reader = Files.newBufferedReader(configFilePath); - - // convert JSON file to map - daemonConfig = gson.fromJson(reader, Config.class); - reader.close(); - - } catch (IOException e) { - e.printStackTrace(); - System.exit(1); - } + // Load configuration file + String initialUserConfigurationPath = jarAbsolutePath.toString() + File.separator + CONFIGURATION_FILE_NAME; + ConfigurationLoaderServiceImpl configurationLoaderService = new ConfigurationLoaderServiceImpl(initialUserConfigurationPath); + Config initialUserConfiguration = configurationLoaderService.getCurrentUserConfiguration(); // Configuration not found we exit the app for now - if (daemonConfig == null) { + if (initialUserConfiguration == null) { LOGGER.error("Configuration file is either empty or malformed, exiting..."); System.exit(1); } - + // Create script directory - if (StringUtils.isBlank(daemonConfig.getScriptDir())) { + if (StringUtils.isBlank(initialUserConfiguration.getScriptDir())) { LOGGER.warn("Missing scriptDir property in configuration file. Will be using 'script' dir"); - daemonConfig.setScriptDir("script"); + initialUserConfiguration.setScriptDir("script"); } - - Path batchPath = Paths.get(jarAbsolutePath + File.separator + daemonConfig.getScriptDir() + File.separator); + + Path batchPath = Paths.get(jarAbsolutePath + File.separator + initialUserConfiguration.getScriptDir() + File.separator); LOGGER.info("Script location:" + batchPath); try { @@ -93,11 +58,28 @@ public static void main(String[] args) throws RuntimeException, IOException, Int // Initialise and run Daemon FullConfiguration configuration = new FullConfiguration(); - configuration.setUserConfiguration(daemonConfig); + configuration.setUserConfiguration(initialUserConfiguration); configuration.setAbsPathHomeFolder(jarAbsolutePath.toString()); - configuration.setAbsPathScriptFolder(configuration.getAbsPathHomeFolder() + File.separator + daemonConfig.getScriptDir() + File.separator); + configuration.setAbsPathScriptFolder(configuration.getAbsPathHomeFolder() + File.separator + initialUserConfiguration.getScriptDir() + File.separator); + Daemon deamon = new Daemon(); while (true) { + + // New configuration detected + if (configurationLoaderService.isConfigurationUpdated(initialUserConfigurationPath)) { + + if (configuration.getUserConfiguration().isLogEverything()) { + LOGGER.info("New configuration detected !"); + } + // Load configuration + Config newUserConfiguration = configurationLoaderService.loadConfiguration(initialUserConfigurationPath); + if (newUserConfiguration != null) { + configuration.setUserConfiguration(newUserConfiguration); + } else { + LOGGER.warn("Cound not load new configuration, will keep using the old one !"); + } + } + deamon.run(configuration); Thread.sleep(10000); } diff --git a/src/main/java/com/smart/home/pc/daemon/service/ConfigurationLoaderService.java b/src/main/java/com/smart/home/pc/daemon/service/ConfigurationLoaderService.java new file mode 100644 index 0000000..e4eab11 --- /dev/null +++ b/src/main/java/com/smart/home/pc/daemon/service/ConfigurationLoaderService.java @@ -0,0 +1,11 @@ +package com.smart.home.pc.daemon.service; + +import com.smart.home.pc.daemon.dto.Config; + +public interface ConfigurationLoaderService { + + public Config loadConfiguration(String configurationPath); + + public boolean isConfigurationUpdated(String configurationPath); + +} diff --git a/src/main/java/com/smart/home/pc/daemon/service/impl/ConfigurationLoaderServiceImpl.java b/src/main/java/com/smart/home/pc/daemon/service/impl/ConfigurationLoaderServiceImpl.java new file mode 100644 index 0000000..83002b6 --- /dev/null +++ b/src/main/java/com/smart/home/pc/daemon/service/impl/ConfigurationLoaderServiceImpl.java @@ -0,0 +1,77 @@ +package com.smart.home.pc.daemon.service.impl; + +import java.util.Date; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import com.smart.home.pc.daemon.dto.Config; +import com.smart.home.pc.daemon.service.ConfigurationLoaderService; +import com.smart.home.pc.daemon.util.FileHelper; + +public class ConfigurationLoaderServiceImpl implements ConfigurationLoaderService { + + private static final Logger LOGGER = LogManager.getLogger(ConfigurationLoaderServiceImpl.class); + + private Date configurationFileLastModifiedDate; + + private Config currentUserConfiguration; + + private FileHelper fileHelper = new FileHelper(); + + public ConfigurationLoaderServiceImpl() { + + } + + public ConfigurationLoaderServiceImpl(String configurationPath) { + loadConfiguration(configurationPath); + } + + @Override + public Config loadConfiguration(String configurationPath) { + Date configurationPathLastModificationDate = fileHelper.getFileLastModificationDate(configurationPath); + // Configuration is found and is a file. + if (configurationPathLastModificationDate != null) { + Config loadedConfiguration = fileHelper.getConfigurationFromPath(configurationPath); + if (loadedConfiguration != null) { + configurationFileLastModifiedDate = configurationPathLastModificationDate; + currentUserConfiguration = loadedConfiguration; + return currentUserConfiguration; + } else { + LOGGER.error("Issue loading configuration file: " + configurationPath); + } + } else { + // Configuration file not found or null + LOGGER.error("The provided configuration path was not found: " + configurationPath); + } + return null; + } + + @Override + public boolean isConfigurationUpdated(String configurationPath) { + if (configurationPath != null) { + Date currentConfigDate = fileHelper.getFileLastModificationDate(configurationPath); + if (currentConfigDate == null || currentConfigDate.equals(configurationFileLastModifiedDate)) { + return false; + } + } + return true; + } + + public Date getConfigurationLoadDate() { + return configurationFileLastModifiedDate; + } + + public void setConfigurationLoadDate(Date configurationLoadDate) { + this.configurationFileLastModifiedDate = configurationLoadDate; + } + + public Config getCurrentUserConfiguration() { + return currentUserConfiguration; + } + + public void setCurrentUserConfiguration(Config currentUserConfiguration) { + this.currentUserConfiguration = currentUserConfiguration; + } + +} diff --git a/src/main/java/com/smart/home/pc/daemon/util/FileHelper.java b/src/main/java/com/smart/home/pc/daemon/util/FileHelper.java new file mode 100644 index 0000000..1c0601c --- /dev/null +++ b/src/main/java/com/smart/home/pc/daemon/util/FileHelper.java @@ -0,0 +1,79 @@ +package com.smart.home.pc.daemon.util; + +import java.io.File; +import java.io.IOException; +import java.io.Reader; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Date; + +import org.apache.commons.lang3.StringUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import com.google.gson.Gson; +import com.smart.home.pc.daemon.dto.Config; + +/** + * Helper class to manage file actions + * + * @author Ramzi + * + */ +public class FileHelper { + + private static final Logger LOGGER = LogManager.getLogger(FileHelper.class); + + private Gson gson = new Gson(); + + /** + * Get last modification date for the given file path + * + * @param filePath, String containing the absolute path of the file + * @return last modification date or null + */ + public Date getFileLastModificationDate(String fileAbsPath) { + if (StringUtils.isEmpty(fileAbsPath)) { + return null; + } + + File configFile = new File(fileAbsPath); + if (configFile.exists()) { + return new Date(configFile.lastModified()); + } + + return null; + } + + /** + * Reads the configuration file as a Json and returns the corresponding object + * + * @param configFilePath + * @return + */ + public Config getConfigurationFromPath(String configurationPath) { + Path configFilePath = Paths.get(configurationPath); + Config userConfiguration = null; + + Reader reader; + try { + reader = Files.newBufferedReader(configFilePath); + + // convert JSON file to map + userConfiguration = gson.fromJson(reader, Config.class); + reader.close(); + + } catch (Exception e) { + e.printStackTrace(); + LOGGER.error("Exception while reading configuration file please check file format: " + configFilePath); + } + + if (userConfiguration == null) { + LOGGER.error("Configuration file is either empty or malformed"); + } + + return userConfiguration; + } + +} diff --git a/src/test/java/com/smart/home/pc/daemon/service/impl/ConfigurationLoaderServiceTest.java b/src/test/java/com/smart/home/pc/daemon/service/impl/ConfigurationLoaderServiceTest.java new file mode 100644 index 0000000..7ee7863 --- /dev/null +++ b/src/test/java/com/smart/home/pc/daemon/service/impl/ConfigurationLoaderServiceTest.java @@ -0,0 +1,126 @@ +package com.smart.home.pc.daemon.service.impl; + +import java.util.Date; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; + +import com.smart.home.pc.daemon.dto.Config; +import com.smart.home.pc.daemon.util.FileHelper; + +@RunWith(MockitoJUnitRunner.class) +public class ConfigurationLoaderServiceTest { + + @InjectMocks + ConfigurationLoaderServiceImpl configurationLoaderServiceImpl = new ConfigurationLoaderServiceImpl(); + + @Mock + FileHelper fileHelper; + + @Test + public void isConfigurationUpdatedInitialLoadTest() { + /* + * Initial configuration, new configuration has a last modification date (file + * FOUND) + * + */ + + configurationLoaderServiceImpl.setConfigurationLoadDate(null); + Mockito.when(fileHelper.getFileLastModificationDate("")).thenReturn(new Date()); + Assert.assertTrue(configurationLoaderServiceImpl.isConfigurationUpdated("")); + + /* + * Initial configuration, new configuration has a last modification date (file + * NOT FOUND) + * + */ + configurationLoaderServiceImpl.setConfigurationLoadDate(null); + Mockito.when(fileHelper.getFileLastModificationDate("")).thenReturn(null); + Assert.assertFalse(configurationLoaderServiceImpl.isConfigurationUpdated("")); + } + + @Test + public void isConfigurationUpdatedAfterInitialLoadTest() { + /* + * Initial configuration is SET we will play with the new configuration last + * modification test + */ + Date lastModificationDate = new Date(); + Date before = new Date(lastModificationDate.getTime() - 10); + Date after = new Date(lastModificationDate.getTime()); + + // New configuration file modification date is same as initial configuration + configurationLoaderServiceImpl.setConfigurationLoadDate(lastModificationDate); + Mockito.when(fileHelper.getFileLastModificationDate("")).thenReturn(lastModificationDate); + Assert.assertFalse(configurationLoaderServiceImpl.isConfigurationUpdated("")); + + // New configuration file modification date is null + configurationLoaderServiceImpl.setConfigurationLoadDate(new Date()); + Mockito.when(fileHelper.getFileLastModificationDate("")).thenReturn(null); + Assert.assertFalse(configurationLoaderServiceImpl.isConfigurationUpdated("")); + + // New configuration last modification is in the future + configurationLoaderServiceImpl.setConfigurationLoadDate(after); // Set last modification + Mockito.when(fileHelper.getFileLastModificationDate("")).thenReturn(before); + Assert.assertTrue(configurationLoaderServiceImpl.isConfigurationUpdated("")); + + // New configuration last modification is in the past + configurationLoaderServiceImpl.setConfigurationLoadDate(before); // Set last modification + Mockito.when(fileHelper.getFileLastModificationDate("")).thenReturn(after); + Assert.assertTrue(configurationLoaderServiceImpl.isConfigurationUpdated("")); + + } + + @Test + public void loadConfigurationTestEmpty() { + Assert.assertNull(configurationLoaderServiceImpl.loadConfiguration(null)); + Assert.assertNull(configurationLoaderServiceImpl.loadConfiguration("")); + Assert.assertNull(configurationLoaderServiceImpl.loadConfiguration(" ")); + } + + @Test + public void loadConfigurationTest() { + + String dummyConfigFilePath = "dummyConfigFilePath"; + String dummyCommandPath = "dummyCommandPath"; + Date lastModificationDate = new Date(); + Date lastModificationDatePast = new Date(lastModificationDate.getTime() - 10); + Config expectedConfiguration = new Config(); + expectedConfiguration.setCommandPath(dummyCommandPath); + + // Configuration file not found + Mockito.when(fileHelper.getFileLastModificationDate(dummyConfigFilePath)).thenReturn(null); + // Execute loading + Assert.assertNull(configurationLoaderServiceImpl.loadConfiguration(dummyConfigFilePath)); + + // Configuration file found but issue in the loading + configurationLoaderServiceImpl.setConfigurationLoadDate(lastModificationDatePast); // Set last configuration modification date in the past + configurationLoaderServiceImpl.setCurrentUserConfiguration(null); + Mockito.when(fileHelper.getFileLastModificationDate(dummyConfigFilePath)).thenReturn(lastModificationDate); + Mockito.when(fileHelper.getConfigurationFromPath(dummyConfigFilePath)).thenReturn(null); // Issue in loading the configuration object + // Execute loading + Assert.assertNull(configurationLoaderServiceImpl.loadConfiguration(dummyConfigFilePath)); + // Modification date should not be altered + Assert.assertFalse(configurationLoaderServiceImpl.getConfigurationLoadDate().equals(lastModificationDate)); + Assert.assertTrue(configurationLoaderServiceImpl.getConfigurationLoadDate().equals(lastModificationDatePast)); + + // Configuration file found and loaded + configurationLoaderServiceImpl.setConfigurationLoadDate(lastModificationDatePast); // Set last configuration modification date in the past + configurationLoaderServiceImpl.setCurrentUserConfiguration(null); + Mockito.when(fileHelper.getFileLastModificationDate(dummyConfigFilePath)).thenReturn(lastModificationDate); + Mockito.when(fileHelper.getConfigurationFromPath(dummyConfigFilePath)).thenReturn(expectedConfiguration); + // Execute loading + Assert.assertNotNull(configurationLoaderServiceImpl.loadConfiguration(dummyConfigFilePath)); + // Modification date should be updated + Assert.assertTrue(configurationLoaderServiceImpl.getConfigurationLoadDate().equals(lastModificationDate)); + // Current configuration should be updated + Assert.assertTrue(configurationLoaderServiceImpl.getCurrentUserConfiguration().getCommandPath().equals(dummyCommandPath)); + + } + +}