diff --git a/core-java-modules/core-java-properties/pom.xml b/core-java-modules/core-java-properties/pom.xml index 67e0204c6e24..cc481127d6a8 100644 --- a/core-java-modules/core-java-properties/pom.xml +++ b/core-java-modules/core-java-properties/pom.xml @@ -1,7 +1,7 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 core-java-properties 0.1.0-SNAPSHOT @@ -14,4 +14,21 @@ 0.0.1-SNAPSHOT - \ No newline at end of file + + 2.11.0 + 1.10.1 + + + + + org.apache.commons + commons-configuration2 + ${apache.commons.version} + + + commons-beanutils + commons-beanutils + ${commons.beanutils.version} + + + diff --git a/core-java-modules/core-java-properties/src/main/java/com/baeldung/core/java/properties/ApacheCommonsPropertyMutator.java b/core-java-modules/core-java-properties/src/main/java/com/baeldung/core/java/properties/ApacheCommonsPropertyMutator.java new file mode 100644 index 000000000000..80a78f43adf4 --- /dev/null +++ b/core-java-modules/core-java-properties/src/main/java/com/baeldung/core/java/properties/ApacheCommonsPropertyMutator.java @@ -0,0 +1,41 @@ +package com.baeldung.core.java.properties; + +import org.apache.commons.configuration2.Configuration; +import org.apache.commons.configuration2.FileBasedConfiguration; +import org.apache.commons.configuration2.PropertiesConfiguration; +import org.apache.commons.configuration2.builder.FileBasedConfigurationBuilder; +import org.apache.commons.configuration2.builder.fluent.Parameters; +import org.apache.commons.configuration2.ex.ConfigurationException; + +public class ApacheCommonsPropertyMutator implements PropertyMutator { + + private final String propertyFileName; + + public ApacheCommonsPropertyMutator(String propertyFileName) { + this.propertyFileName = propertyFileName; + } + + @Override + public String getProperty(String key) throws ConfigurationException { + FileBasedConfigurationBuilder builder = getAppPropertiesConfigBuilder(); + Configuration properties = builder.getConfiguration(); + + return (String) properties.getProperty(key); + } + + @Override + public void addOrUpdateProperty(String key, String value) throws ConfigurationException { + FileBasedConfigurationBuilder builder = getAppPropertiesConfigBuilder(); + Configuration configuration = builder.getConfiguration(); + + configuration.setProperty(key, value); + builder.save(); + } + + private FileBasedConfigurationBuilder getAppPropertiesConfigBuilder() { + Parameters params = new Parameters(); + + return new FileBasedConfigurationBuilder(PropertiesConfiguration.class).configure(params.properties() + .setFileName(propertyFileName)); + } +} diff --git a/core-java-modules/core-java-properties/src/main/java/com/baeldung/core/java/properties/FileAPIPropertyMutator.java b/core-java-modules/core-java-properties/src/main/java/com/baeldung/core/java/properties/FileAPIPropertyMutator.java new file mode 100644 index 000000000000..13a4b023f1e0 --- /dev/null +++ b/core-java-modules/core-java-properties/src/main/java/com/baeldung/core/java/properties/FileAPIPropertyMutator.java @@ -0,0 +1,78 @@ +package com.baeldung.core.java.properties; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.List; + +public class FileAPIPropertyMutator { + + private final String propertyFileName; + private final PropertyLoader propertyLoader; + + public FileAPIPropertyMutator(String propertyFileName, PropertyLoader propertyLoader) { + this.propertyFileName = propertyFileName; + this.propertyLoader = propertyLoader; + } + + public String getPropertyKeyWithValue(int lineNumber) throws IOException { + List fileLines = getFileLines(); + // depending on the system, sometimes the first line will be a comment with a timestamp of the file read + // the next line will make this method compatible with all systems + if (fileLines.get(0).startsWith("#")) { + lineNumber++; + } + + return fileLines.get(lineNumber); + } + + public String getLastPropertyKeyWithValue() throws IOException { + List fileLines = getFileLines(); + + return fileLines.get(fileLines.size() - 1); + } + + public void addPropertyKeyWithValue(String keyAndValue) throws IOException { + File propertiesFile = new File(propertyLoader.getFilePathFromResources(propertyFileName)); + List fileContent = getFileLines(propertiesFile); + + fileContent.add(keyAndValue); + Files.write(propertiesFile.toPath(), fileContent, StandardCharsets.UTF_8); + } + + public int updateProperty(String oldKeyValuePair, String newKeyValuePair) throws IOException { + File propertiesFile = new File(propertyLoader.getFilePathFromResources(propertyFileName)); + List fileContent = getFileLines(propertiesFile); + int updatedIndex = -1; + + for (int i = 0; i < fileContent.size(); i++) { + if (fileContent.get(i) + .replaceAll("\\s+", "") + .equals(oldKeyValuePair)) { + fileContent.set(i, newKeyValuePair); + updatedIndex = i; + break; + } + } + Files.write(propertiesFile.toPath(), fileContent, StandardCharsets.UTF_8); + + // depending on the system, sometimes the first line will be a comment with a timestamp of the file read + // the next line will make this method compatible with all systems + if (fileContent.get(0).startsWith("#")) { + updatedIndex--; + } + + return updatedIndex; + } + + private List getFileLines() throws IOException { + File propertiesFile = new File(propertyLoader.getFilePathFromResources(propertyFileName)); + return getFileLines(propertiesFile); + } + + private List getFileLines(File propertiesFile) throws IOException { + return new ArrayList<>(Files.readAllLines(propertiesFile.toPath(), StandardCharsets.UTF_8)); + } +} diff --git a/core-java-modules/core-java-properties/src/main/java/com/baeldung/core/java/properties/FileStreamsPropertyMutator.java b/core-java-modules/core-java-properties/src/main/java/com/baeldung/core/java/properties/FileStreamsPropertyMutator.java new file mode 100644 index 000000000000..7ca19654372a --- /dev/null +++ b/core-java-modules/core-java-properties/src/main/java/com/baeldung/core/java/properties/FileStreamsPropertyMutator.java @@ -0,0 +1,33 @@ +package com.baeldung.core.java.properties; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Properties; + +public class FileStreamsPropertyMutator implements PropertyMutator { + + private final String propertyFileName; + private final PropertyLoader propertyLoader; + + public FileStreamsPropertyMutator(String propertyFileName, PropertyLoader propertyLoader) { + this.propertyFileName = propertyFileName; + this.propertyLoader = propertyLoader; + } + + @Override + public String getProperty(String key) throws IOException { + Properties properties = propertyLoader.fromFile(propertyFileName); + + return properties.getProperty(key); + } + + @Override + public void addOrUpdateProperty(String key, String value) throws IOException { + Properties properties = propertyLoader.fromFile(propertyFileName); + properties.setProperty(key, value); + + FileOutputStream out = new FileOutputStream(propertyLoader.getFilePathFromResources(propertyFileName)); + properties.store(out, null); + out.close(); + } +} diff --git a/core-java-modules/core-java-properties/src/main/java/com/baeldung/core/java/properties/PropertyLoader.java b/core-java-modules/core-java-properties/src/main/java/com/baeldung/core/java/properties/PropertyLoader.java new file mode 100644 index 000000000000..fb016afcca08 --- /dev/null +++ b/core-java-modules/core-java-properties/src/main/java/com/baeldung/core/java/properties/PropertyLoader.java @@ -0,0 +1,29 @@ +package com.baeldung.core.java.properties; + +import java.io.FileInputStream; +import java.io.IOException; +import java.net.URL; +import java.util.Objects; +import java.util.Properties; + +public class PropertyLoader { + + public Properties fromFile(String filename) throws IOException { + String appPropertiesFileName = getFilePathFromResources(filename); + FileInputStream in = new FileInputStream(appPropertiesFileName); + Properties properties = new Properties(); + + properties.load(in); + in.close(); + + return properties; + } + + public String getFilePathFromResources(String filename) { + URL resourceUrl = getClass().getClassLoader() + .getResource(filename); + Objects.requireNonNull(resourceUrl, "Property file with name [" + filename + "] was not found."); + + return resourceUrl.getFile(); + } +} diff --git a/core-java-modules/core-java-properties/src/main/java/com/baeldung/core/java/properties/PropertyMutator.java b/core-java-modules/core-java-properties/src/main/java/com/baeldung/core/java/properties/PropertyMutator.java new file mode 100644 index 000000000000..a3da91e7b531 --- /dev/null +++ b/core-java-modules/core-java-properties/src/main/java/com/baeldung/core/java/properties/PropertyMutator.java @@ -0,0 +1,12 @@ +package com.baeldung.core.java.properties; + +import java.io.IOException; + +import org.apache.commons.configuration2.ex.ConfigurationException; + +public interface PropertyMutator { + + String getProperty(String key) throws IOException, ConfigurationException; + + void addOrUpdateProperty(String key, String value) throws IOException, ConfigurationException; +} diff --git a/core-java-modules/core-java-properties/src/main/java/com/baeldung/core/java/properties/XMLFilePropertyMutator.java b/core-java-modules/core-java-properties/src/main/java/com/baeldung/core/java/properties/XMLFilePropertyMutator.java new file mode 100644 index 000000000000..63b63c778ea6 --- /dev/null +++ b/core-java-modules/core-java-properties/src/main/java/com/baeldung/core/java/properties/XMLFilePropertyMutator.java @@ -0,0 +1,58 @@ +package com.baeldung.core.java.properties; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.Objects; +import java.util.Properties; + +public class XMLFilePropertyMutator implements PropertyMutator { + + private final String propertyFileName; + + public XMLFilePropertyMutator(String propertyFileName) { + this.propertyFileName = propertyFileName; + } + + @Override + public String getProperty(String key) throws IOException { + Properties properties = loadProperties(); + + return properties.getProperty(key); + } + + @Override + public void addOrUpdateProperty(String key, String value) throws IOException { + String filePath = getXMLAppPropertiesWithFileStreamFilePath(); + Properties properties = loadProperties(filePath); + + try (OutputStream os = Files.newOutputStream(Paths.get(filePath))) { + properties.setProperty(key, value); + properties.storeToXML(os, null); + } + } + + private Properties loadProperties() throws IOException { + return loadProperties(getXMLAppPropertiesWithFileStreamFilePath()); + } + + private Properties loadProperties(String filepath) throws IOException { + Properties props = new Properties(); + try (InputStream is = Files.newInputStream(Paths.get(filepath))) { + props.loadFromXML(is); + } + + return props; + } + + String getXMLAppPropertiesWithFileStreamFilePath() { + URL resourceUrl = getClass().getClassLoader() + .getResource(propertyFileName); + Objects.requireNonNull(resourceUrl, "Property file with name [" + propertyFileName + "] was not found."); + + return resourceUrl.getFile(); + } +} diff --git a/core-java-modules/core-java-properties/src/test/java/com/baeldung/core/java/properties/ApacheCommonsPropertyMutatorUnitTest.java b/core-java-modules/core-java-properties/src/test/java/com/baeldung/core/java/properties/ApacheCommonsPropertyMutatorUnitTest.java new file mode 100644 index 000000000000..4213d6953c33 --- /dev/null +++ b/core-java-modules/core-java-properties/src/test/java/com/baeldung/core/java/properties/ApacheCommonsPropertyMutatorUnitTest.java @@ -0,0 +1,56 @@ +package com.baeldung.core.java.properties; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Properties; + +import org.apache.commons.configuration2.ex.ConfigurationException; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class ApacheCommonsPropertyMutatorUnitTest { + + private static final String PROPERTY_FILE_NAME = "app.properties"; + private final PropertyLoader propertyLoader = new PropertyLoader(); + private Properties initialProperties; + + private final ApacheCommonsPropertyMutator propertyMutator = new ApacheCommonsPropertyMutator(PROPERTY_FILE_NAME); + + @BeforeEach + public void loadInitialPropertiesFromFile() throws IOException { + initialProperties = propertyLoader.fromFile(PROPERTY_FILE_NAME); + } + + @AfterEach + public void restoreInitialPropertiesToFile() throws IOException { + FileOutputStream out = new FileOutputStream(propertyLoader.getFilePathFromResources(PROPERTY_FILE_NAME)); + initialProperties.store(out, null); + out.close(); + } + + @Test + public void givenApacheCommons_whenAddNonExistingProperty_thenNewPropertyWithoutAffectingOtherProperties() throws ConfigurationException { + assertNull(propertyMutator.getProperty("new.property")); + assertEquals("TestApp", propertyMutator.getProperty("name")); + + propertyMutator.addOrUpdateProperty("new.property", "new-value"); + + assertEquals("new-value", propertyMutator.getProperty("new.property")); + assertEquals("TestApp", propertyMutator.getProperty("name")); + } + + @Test + public void givenApacheCommons_whenUpdateExistingProperty_thenUpdatedPropertyWithoutAffectingOtherProperties() throws ConfigurationException { + assertEquals("1.0", propertyMutator.getProperty("version")); + assertEquals("TestApp", propertyMutator.getProperty("name")); + + propertyMutator.addOrUpdateProperty("version", "2.0"); + + assertEquals("2.0", propertyMutator.getProperty("version")); + assertEquals("TestApp", propertyMutator.getProperty("name")); + } +} diff --git a/core-java-modules/core-java-properties/src/test/java/com/baeldung/core/java/properties/FileAPIPropertyMutatorUnitTest.java b/core-java-modules/core-java-properties/src/test/java/com/baeldung/core/java/properties/FileAPIPropertyMutatorUnitTest.java new file mode 100644 index 000000000000..1f66d34a04c1 --- /dev/null +++ b/core-java-modules/core-java-properties/src/test/java/com/baeldung/core/java/properties/FileAPIPropertyMutatorUnitTest.java @@ -0,0 +1,52 @@ +package com.baeldung.core.java.properties; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Properties; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class FileAPIPropertyMutatorUnitTest { + + private static final String PROPERTY_FILE_NAME = "app.properties"; + private final PropertyLoader propertyLoader = new PropertyLoader(); + private Properties initialProperties; + + private final FileAPIPropertyMutator propertyMutator = new FileAPIPropertyMutator(PROPERTY_FILE_NAME, propertyLoader); + + @BeforeEach + public void loadInitialPropertiesFromFile() throws IOException { + initialProperties = propertyLoader.fromFile(PROPERTY_FILE_NAME); + } + + @AfterEach + public void restoreInitialPropertiesToFile() throws IOException { + FileOutputStream out = new FileOutputStream(propertyLoader.getFilePathFromResources(PROPERTY_FILE_NAME)); + initialProperties.store(out, null); + out.close(); + } + + @Test + public void givenFilesAPI_whenAddNonExistingProperty_thenNewPropertyWithoutAffectingOtherProperties() throws IOException { + assertEquals("name=TestApp", propertyMutator.getPropertyKeyWithValue(1)); + + propertyMutator.addPropertyKeyWithValue("new.property=new-value"); + + assertEquals("new.property=new-value", propertyMutator.getLastPropertyKeyWithValue()); + assertEquals("name=TestApp", propertyMutator.getPropertyKeyWithValue(1)); + } + + @Test + public void givenFilesAPI_whenUpdateExistingProperty_thenUpdatedPropertyWithoutAffectingOtherProperties() throws IOException { + assertEquals("name=TestApp", propertyMutator.getPropertyKeyWithValue(1)); + + int updatedPropertyIndex = propertyMutator.updateProperty("version=1.0", "version=2.0"); + + assertEquals("version=2.0", propertyMutator.getPropertyKeyWithValue(updatedPropertyIndex)); + assertEquals("name=TestApp", propertyMutator.getPropertyKeyWithValue(1)); + } +} diff --git a/core-java-modules/core-java-properties/src/test/java/com/baeldung/core/java/properties/FileStreamsPropertyMutatorUnitTest.java b/core-java-modules/core-java-properties/src/test/java/com/baeldung/core/java/properties/FileStreamsPropertyMutatorUnitTest.java new file mode 100644 index 000000000000..a6c20c0225ea --- /dev/null +++ b/core-java-modules/core-java-properties/src/test/java/com/baeldung/core/java/properties/FileStreamsPropertyMutatorUnitTest.java @@ -0,0 +1,55 @@ +package com.baeldung.core.java.properties; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Properties; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class FileStreamsPropertyMutatorUnitTest { + + private static final String PROPERTY_FILE_NAME = "app.properties"; + private final PropertyLoader propertyLoader = new PropertyLoader(); + private Properties initialProperties; + + private final FileStreamsPropertyMutator propertyMutator = new FileStreamsPropertyMutator(PROPERTY_FILE_NAME, propertyLoader); + + @BeforeEach + public void loadInitialPropertiesFromFile() throws IOException { + initialProperties = propertyLoader.fromFile(PROPERTY_FILE_NAME); + } + + @AfterEach + public void restoreInitialPropertiesToFile() throws IOException { + FileOutputStream out = new FileOutputStream(propertyLoader.getFilePathFromResources(PROPERTY_FILE_NAME)); + initialProperties.store(out, null); + out.close(); + } + + @Test + public void givenFileStreams_whenAddNonExistingProperty_thenNewPropertyWithoutAffectingOtherProperties() throws IOException { + assertEquals("TestApp", propertyMutator.getProperty("name")); + assertNull(propertyMutator.getProperty("new.property")); + + propertyMutator.addOrUpdateProperty("new.property", "new-value"); + + assertEquals("new-value", propertyMutator.getProperty("new.property")); + assertEquals("TestApp", propertyMutator.getProperty("name")); + } + + @Test + public void givenFileStreams_whenUpdateExistingProperty_thenUpdatedPropertyWithoutAffectingOtherProperties() throws IOException { + assertEquals("1.0", propertyMutator.getProperty("version")); + assertEquals("TestApp", propertyMutator.getProperty("name")); + + propertyMutator.addOrUpdateProperty("version", "2.0"); + + assertEquals("2.0", propertyMutator.getProperty("version")); + assertEquals("TestApp", propertyMutator.getProperty("name")); + } +} diff --git a/core-java-modules/core-java-properties/src/test/java/com/baeldung/core/java/properties/XMLFilePropertyMutatorUnitTest.java b/core-java-modules/core-java-properties/src/test/java/com/baeldung/core/java/properties/XMLFilePropertyMutatorUnitTest.java new file mode 100644 index 000000000000..aa6ab4be90ec --- /dev/null +++ b/core-java-modules/core-java-properties/src/test/java/com/baeldung/core/java/properties/XMLFilePropertyMutatorUnitTest.java @@ -0,0 +1,59 @@ +package com.baeldung.core.java.properties; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.Properties; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class XMLFilePropertyMutatorUnitTest { + + Properties initialProperties = new Properties(); + XMLFilePropertyMutator propertyMutator = new XMLFilePropertyMutator("icons.xml"); + + @BeforeEach + public void setUp() throws IOException { + String filepath = propertyMutator.getXMLAppPropertiesWithFileStreamFilePath(); + try (InputStream is = Files.newInputStream(Paths.get(filepath))) { + initialProperties.loadFromXML(is); + } + } + + @AfterEach + public void tearDown() throws IOException { + String filepath = propertyMutator.getXMLAppPropertiesWithFileStreamFilePath(); + try (OutputStream os = Files.newOutputStream(Paths.get(filepath))) { + initialProperties.storeToXML(os, null); + } + } + + @Test + public void givenXMLPropertyFile_whenAddNonExistingProperty_thenNewPropertyWithoutAffectingOtherProperties() throws IOException { + assertEquals("icon1.jpg", propertyMutator.getProperty("fileIcon")); + assertNull(propertyMutator.getProperty("new.property")); + + propertyMutator.addOrUpdateProperty("new.property", "new-value"); + + assertEquals("new-value", propertyMutator.getProperty("new.property")); + assertEquals("icon1.jpg", propertyMutator.getProperty("fileIcon")); + } + + @Test + public void givenXMLPropertyFile_whenUpdateExistingProperty_thenUpdatedPropertyWithoutAffectingOtherProperties() throws IOException { + assertEquals("icon1.jpg", propertyMutator.getProperty("fileIcon")); + assertEquals("icon2.jpg", propertyMutator.getProperty("imageIcon")); + + propertyMutator.addOrUpdateProperty("fileIcon", "icon5.jpg"); + + assertEquals("icon5.jpg", propertyMutator.getProperty("fileIcon")); + assertEquals("icon2.jpg", propertyMutator.getProperty("imageIcon")); + } +}