From 3240f5b820d3f79369d89fb3bd30d8796b4a4c65 Mon Sep 17 00:00:00 2001 From: brokenhardisk Date: Sun, 28 Apr 2024 19:06:40 +0200 Subject: [PATCH] BAEL-7617: Intro to Apache Commons Configuration (#16281) * BAEL-7617: Intro to Apache Commons Configuration * BAEL-7617: Review Comments * BAEL-7617: Review Comments * BAEL-7617: Review Comments --- libraries-apache-commons-2/pom.xml | 18 ++ .../commons/configuration/CustomDecoder.java | 12 ++ .../configuration/ExternalServices.java | 7 + .../ConfigurationClassUnitTest.java | 169 ++++++++++++++++++ ...FileBasedConfigurationBuilderUnitTest.java | 70 ++++++++ ...MultiFileConfigurationBuilderUnitTest.java | 28 +++ .../resources/configuration/file.properties | 8 + .../resources/configuration/file1.properties | 4 + .../resources/configuration/hierarchical.xml | 14 ++ .../configuration/tenant-A.properties | 1 + .../configuration/validation-sample.dtd | 13 ++ 11 files changed, 344 insertions(+) create mode 100644 libraries-apache-commons-2/src/main/java/com/baeldung/commons/configuration/CustomDecoder.java create mode 100644 libraries-apache-commons-2/src/main/java/com/baeldung/commons/configuration/ExternalServices.java create mode 100644 libraries-apache-commons-2/src/test/java/com/baeldung/commons/configuration/ConfigurationClassUnitTest.java create mode 100644 libraries-apache-commons-2/src/test/java/com/baeldung/commons/configuration/FileBasedConfigurationBuilderUnitTest.java create mode 100644 libraries-apache-commons-2/src/test/java/com/baeldung/commons/configuration/MultiFileConfigurationBuilderUnitTest.java create mode 100644 libraries-apache-commons-2/src/test/resources/configuration/file.properties create mode 100644 libraries-apache-commons-2/src/test/resources/configuration/file1.properties create mode 100644 libraries-apache-commons-2/src/test/resources/configuration/hierarchical.xml create mode 100644 libraries-apache-commons-2/src/test/resources/configuration/tenant-A.properties create mode 100644 libraries-apache-commons-2/src/test/resources/configuration/validation-sample.dtd diff --git a/libraries-apache-commons-2/pom.xml b/libraries-apache-commons-2/pom.xml index 0f00bf5d84..dd1627f3ed 100644 --- a/libraries-apache-commons-2/pom.xml +++ b/libraries-apache-commons-2/pom.xml @@ -44,6 +44,21 @@ ${mockftpserver.version} test + + org.apache.commons + commons-configuration2 + ${commons-configuration2.version} + + + commons-beanutils + commons-beanutils + ${commons-beanutils.version} + + + org.apache.commons + commons-jexl + ${commons-jexl.version} + org.tukaani xz @@ -63,6 +78,9 @@ 1.10.0 3.6 2.7.1 + 2.10.0 + 1.9.4 + 2.1.1 1.9 1.5.5-11 diff --git a/libraries-apache-commons-2/src/main/java/com/baeldung/commons/configuration/CustomDecoder.java b/libraries-apache-commons-2/src/main/java/com/baeldung/commons/configuration/CustomDecoder.java new file mode 100644 index 0000000000..909ce80df7 --- /dev/null +++ b/libraries-apache-commons-2/src/main/java/com/baeldung/commons/configuration/CustomDecoder.java @@ -0,0 +1,12 @@ +package com.baeldung.commons.configuration; + +import org.apache.commons.configuration2.ConfigurationDecoder; +import org.apache.commons.net.util.Base64; + +public class CustomDecoder implements ConfigurationDecoder { + + @Override + public String decode(String encodedValue) { + return new String(Base64.decodeBase64(encodedValue)); + } +} diff --git a/libraries-apache-commons-2/src/main/java/com/baeldung/commons/configuration/ExternalServices.java b/libraries-apache-commons-2/src/main/java/com/baeldung/commons/configuration/ExternalServices.java new file mode 100644 index 0000000000..ace4ac0c4a --- /dev/null +++ b/libraries-apache-commons-2/src/main/java/com/baeldung/commons/configuration/ExternalServices.java @@ -0,0 +1,7 @@ +package com.baeldung.commons.configuration; + +public class ExternalServices { + + public static final String BAELDUNG_WEBSITE = "https://www.baeldung.com"; + +} diff --git a/libraries-apache-commons-2/src/test/java/com/baeldung/commons/configuration/ConfigurationClassUnitTest.java b/libraries-apache-commons-2/src/test/java/com/baeldung/commons/configuration/ConfigurationClassUnitTest.java new file mode 100644 index 0000000000..f6e15b9809 --- /dev/null +++ b/libraries-apache-commons-2/src/test/java/com/baeldung/commons/configuration/ConfigurationClassUnitTest.java @@ -0,0 +1,169 @@ +package com.baeldung.commons.configuration; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.File; +import java.util.List; +import java.util.NoSuchElementException; + +import org.apache.commons.configuration2.AbstractConfiguration; +import org.apache.commons.configuration2.Configuration; +import org.apache.commons.configuration2.PropertiesConfiguration; +import org.apache.commons.configuration2.XMLConfiguration; +import org.apache.commons.configuration2.builder.fluent.Configurations; +import org.apache.commons.configuration2.convert.DefaultListDelimiterHandler; +import org.apache.commons.configuration2.ex.ConfigurationException; +import org.apache.commons.configuration2.ex.ConversionException; +import org.junit.jupiter.api.Test; + +class ConfigurationClassUnitTest { + + @Test + void givenPropertiesFile_whenReadingWithConfigurationClass_thenIsLoaded() throws ConfigurationException { + Configurations configs = new Configurations(); + Configuration config = configs.properties(new File("src/test/resources/configuration/file.properties")); + String dbHost = config.getString("db.host"); + int dbPort = config.getInt("db.port"); + String dbUser = config.getString("db.user"); + String dbPassword = config.getString("undefinedKey", "defaultValue"); + assertEquals("baeldung.com", dbHost); + assertEquals(9999, dbPort); + assertEquals("admin", dbUser); + assertEquals("defaultValue", dbPassword); + } + + @Test + void givenXMLFile_whenReadingWithConfigurationClass_thenIsLoaded() throws ConfigurationException { + Configurations configs = new Configurations(); + XMLConfiguration config = configs.xml(new File("src/test/resources/configuration/hierarchical.xml")); + String appender = config.getString("appender[@name]"); + List encoderPatterns = config.getList(String.class, "appender.encoder.pattern"); + String pattern1 = config.getString("appender.encoder.pattern(0)"); + assertEquals("STDOUT", appender); + assertEquals(2, encoderPatterns.size()); + assertEquals("Pattern1", pattern1); + } + + @Test + void givenPropertiesFile_whenCopyingConfiguration_thenIsSuccessful() throws ConfigurationException { + Configurations configs = new Configurations(); + Configuration baseConfig = configs.properties(new File("src/test/resources/configuration/file.properties")); + Configuration subConfig = new PropertiesConfiguration(); + subConfig.addProperty("db.host", "baeldung"); + subConfig.addProperty("db.driver", "dummyDriver"); + ((AbstractConfiguration) subConfig).copy(baseConfig); + String dbHost = subConfig.getString("db.host"); + String dbDriver = subConfig.getString("db.driver"); + int dbPort = subConfig.getInt("db.port"); + String dbUser = subConfig.getString("db.user"); + assertEquals("baeldung.com", dbHost); + assertEquals(9999, dbPort); + assertEquals("admin", dbUser); + assertEquals("dummyDriver", dbDriver); + } + + @Test + public void givenPropertiesFile_whenAppendingConfiguration_thenIsSuccessful() throws ConfigurationException { + Configurations configs = new Configurations(); + Configuration baseConfig = configs.properties(new File("src/test/resources/configuration/file.properties")); + Configuration subConfig = new PropertiesConfiguration(); + subConfig.addProperty("db.host", "baeldung"); + subConfig.addProperty("db.driver", "dummyDriver"); + ((AbstractConfiguration) subConfig).append(baseConfig); + String dbHost = subConfig.getString("db.host"); + String dbDriver = subConfig.getString("db.driver"); + int dbPort = subConfig.getInt("db.port"); + String dbUser = subConfig.getString("db.user"); + assertEquals("baeldung", dbHost); + assertEquals(9999, dbPort); + assertEquals("admin", dbUser); + assertEquals("dummyDriver", dbDriver); + } + + @Test + void givenXMLFile_whenCloningConfiguration_thenIsSuccessful() throws ConfigurationException { + Configurations configs = new Configurations(); + XMLConfiguration baseConfig = configs.xml(new File("src/test/resources/configuration/hierarchical.xml")); + XMLConfiguration subConfig = new XMLConfiguration(); + //subConfig = (XMLConfiguration) baseConfig.clone(); + subConfig = new XMLConfiguration(baseConfig); + String appender = subConfig.getString("appender[@name]"); + List encoderPatterns = subConfig.getList(String.class, "appender.encoder.pattern"); + String pattern1 = subConfig.getString("appender.encoder.pattern(0)"); + assertEquals("STDOUT", appender); + assertEquals(2, encoderPatterns.size()); + assertEquals("Pattern1", pattern1); + } + + @Test + void givenEncodedProperty_whenCustomDecoderImplemented_thenIsSuccessful() throws ConfigurationException { + Configurations configs = new Configurations(); + Configuration config = configs.properties(new File("src/test/resources/configuration/file.properties")); + ((AbstractConfiguration) config).setConfigurationDecoder(new CustomDecoder()); + assertEquals("mySecretString", config.getEncodedString("db.password")); + } + + @Test + void whenDataTypeConversionAttempted_thenIsSuccessful() { + Configuration config = new PropertiesConfiguration(); + config.addProperty("stringProperty", "This is a string"); + config.addProperty("numericProperty", "9999"); + config.addProperty("booleanProperty", "true"); + assertEquals("This is a string", config.getString("stringProperty")); + assertEquals(9999, config.getInt("numericProperty")); + assertTrue(config.getBoolean("booleanProperty")); + } + + @Test + void whenDataTypeConversionAttempted_thenThrowsException() { + Configuration config = new PropertiesConfiguration(); + config.addProperty("numericProperty", "9999a"); + assertThrows(ConversionException.class, () -> config.getInt("numericProperty")); + } + + @Test + void whenInterpolationIsAttempted_thenIsSuccessful() throws ConfigurationException { + System.setProperty("user.name", "Baeldung"); + Configurations configs = new Configurations(); + Configuration config = configs.properties(new File("src/test/resources/configuration/file.properties")); + String dbUrl = config.getString("db.url"); + String userName = config.getString("db.username"); + String externalService = config.getString("db.external-service"); + assertEquals("baeldung.com:9999", dbUrl); + assertEquals("Baeldung", userName); + assertEquals("https://www.baeldung.com", externalService); + } + + @Test + void whenDelimiterIsSpecified_thenMultiValuePropertyIsLoaded() { + PropertiesConfiguration propertiesConfig = new PropertiesConfiguration(); + propertiesConfig.setListDelimiterHandler(new DefaultListDelimiterHandler(';')); + propertiesConfig.addProperty("delimitedProperty", "admin;read-only;read-write"); + propertiesConfig.addProperty("arrayProperty", "value1;value2"); + List delimitedProperties = propertiesConfig.getList("delimitedProperty"); + String[] arrayProperties = propertiesConfig.getStringArray("arrayProperty"); + assertEquals(3, delimitedProperties.size()); + assertEquals("admin", delimitedProperties.get(0)); + assertEquals(2, arrayProperties.length); + assertEquals("value1", propertiesConfig.getString("arrayProperty")); + } + + @Test + void whenPropertiesAreMissing_thenIsHandled() { + PropertiesConfiguration propertiesConfig = new PropertiesConfiguration(); + String objectProperty = propertiesConfig.getString("anyProperty"); + int primitiveProperty = propertiesConfig.getInt("anyProperty", 1); + assertNull(objectProperty); + assertEquals(1, primitiveProperty); + } + + @Test + void whenPropertiesAreMissing_thenExceptionIsThrown() { + PropertiesConfiguration propertiesConfig = new PropertiesConfiguration(); + assertThrows(NoSuchElementException.class, () -> propertiesConfig.getInt("anyProperty")); + } + +} diff --git a/libraries-apache-commons-2/src/test/java/com/baeldung/commons/configuration/FileBasedConfigurationBuilderUnitTest.java b/libraries-apache-commons-2/src/test/java/com/baeldung/commons/configuration/FileBasedConfigurationBuilderUnitTest.java new file mode 100644 index 0000000000..2d9f6f2c14 --- /dev/null +++ b/libraries-apache-commons-2/src/test/java/com/baeldung/commons/configuration/FileBasedConfigurationBuilderUnitTest.java @@ -0,0 +1,70 @@ +package com.baeldung.commons.configuration; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.configuration2.Configuration; +import org.apache.commons.configuration2.FileBasedConfiguration; +import org.apache.commons.configuration2.PropertiesConfiguration; +import org.apache.commons.configuration2.XMLConfiguration; +import org.apache.commons.configuration2.builder.FileBasedConfigurationBuilder; +import org.apache.commons.configuration2.builder.fluent.Parameters; +import org.apache.commons.configuration2.ex.ConfigurationException; +import org.apache.commons.configuration2.interpol.ConfigurationInterpolator; +import org.apache.commons.configuration2.interpol.ExprLookup; +import org.apache.commons.configuration2.interpol.Lookup; +import org.junit.jupiter.api.Test; + +class FileBasedConfigurationBuilderUnitTest { + + @Test + void whenReadingPropertiesFile_thenIsSuccessful() throws ConfigurationException { + Parameters params = new Parameters(); + FileBasedConfigurationBuilder builder = new FileBasedConfigurationBuilder( + PropertiesConfiguration.class).configure(params.properties() + .setFileName("src/test/resources/configuration/file1.properties")); + Configuration config = builder.getConfiguration(); + String dbHost = config.getString("db.host"); + int dbPort = config.getInt("db.port"); + String dbUser = config.getString("db.user"); + assertEquals("baeldung.com", dbHost); + assertEquals(9999, dbPort); + assertEquals("admin", dbUser); + } + + @Test + void whenReadingXMLFile_thenIsSuccessful() throws ConfigurationException { + Parameters params = new Parameters(); + FileBasedConfigurationBuilder builder = new FileBasedConfigurationBuilder<>(XMLConfiguration.class).configure(params.xml() + .setFileName("src/test/resources/configuration/hierarchical.xml") + .setValidating(true)); + XMLConfiguration config = builder.getConfiguration(); + String appender = config.getString("appender[@name]"); + List encoderPatterns = config.getList(String.class, "appender.encoder.pattern"); + assertEquals("STDOUT", appender); + assertEquals(2, encoderPatterns.size()); + } + + @Test + void whenExpressionEvaluationIsAttempted_thenIsSuccessful() throws ConfigurationException { + System.setProperty("user.home", "/usr/lib"); + Parameters params = new Parameters(); + Map lookups = new HashMap<>(ConfigurationInterpolator.getDefaultPrefixLookups()); + ExprLookup.Variables variables = new ExprLookup.Variables(); + variables.add(new ExprLookup.Variable("System", "Class:java.lang.System")); + ExprLookup exprLookup = new ExprLookup(variables); + exprLookup.setInterpolator(new ConfigurationInterpolator()); + lookups.put("expr", exprLookup); + FileBasedConfigurationBuilder builder = new FileBasedConfigurationBuilder( + PropertiesConfiguration.class).configure(params.properties() + .setFileName("src/test/resources/configuration/file1.properties") + .setPrefixLookups(lookups)); + Configuration config = builder.getConfiguration(); + String dbDumpLocation = config.getString("db.data-dump-location"); + assertEquals("/usr/lib/dump.dat", dbDumpLocation); + } + +} diff --git a/libraries-apache-commons-2/src/test/java/com/baeldung/commons/configuration/MultiFileConfigurationBuilderUnitTest.java b/libraries-apache-commons-2/src/test/java/com/baeldung/commons/configuration/MultiFileConfigurationBuilderUnitTest.java new file mode 100644 index 0000000000..964a3a6049 --- /dev/null +++ b/libraries-apache-commons-2/src/test/java/com/baeldung/commons/configuration/MultiFileConfigurationBuilderUnitTest.java @@ -0,0 +1,28 @@ +package com.baeldung.commons.configuration; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.apache.commons.configuration2.Configuration; +import org.apache.commons.configuration2.PropertiesConfiguration; +import org.apache.commons.configuration2.builder.combined.MultiFileConfigurationBuilder; +import org.apache.commons.configuration2.builder.fluent.Parameters; +import org.apache.commons.configuration2.ex.ConfigurationException; +import org.apache.commons.configuration2.interpol.ConfigurationInterpolator; +import org.junit.jupiter.api.Test; + +class MultiFileConfigurationBuilderUnitTest { + + @Test + void givenMultiplePropertyFiles_whenReadingWithMultiFileConfigurationBuilder_thenIsLoaded() throws ConfigurationException { + System.setProperty("tenant", "A"); + String filePattern = "src/test/resources/configuration/tenant-${sys:tenant}.properties"; + MultiFileConfigurationBuilder builder = new MultiFileConfigurationBuilder<>(PropertiesConfiguration.class).configure( + new Parameters().multiFile() + .setFilePattern(filePattern) + .setPrefixLookups(ConfigurationInterpolator.getDefaultPrefixLookups())); + Configuration config = builder.getConfiguration(); + String tenantAName = config.getString("name"); + + assertEquals("Tenant A", tenantAName); + } +} diff --git a/libraries-apache-commons-2/src/test/resources/configuration/file.properties b/libraries-apache-commons-2/src/test/resources/configuration/file.properties new file mode 100644 index 0000000000..02f10f8e3a --- /dev/null +++ b/libraries-apache-commons-2/src/test/resources/configuration/file.properties @@ -0,0 +1,8 @@ +db.host=baeldung.com +db.port=9999 +db.user=admin +db.password=bXlTZWNyZXRTdHJpbmc= +db.url=${db.host}:${db.port} +db.username=${sys:user.name} +db.external-service=${const:com.baeldung.commons.configuration.ExternalServices.BAELDUNG_WEBSITE} +db.data-dump-location=${expr:System.getProperty("user.home")}/dump.dat \ No newline at end of file diff --git a/libraries-apache-commons-2/src/test/resources/configuration/file1.properties b/libraries-apache-commons-2/src/test/resources/configuration/file1.properties new file mode 100644 index 0000000000..8a5b0c7013 --- /dev/null +++ b/libraries-apache-commons-2/src/test/resources/configuration/file1.properties @@ -0,0 +1,4 @@ +db.host=baeldung.com + +include=file.properties +includeOptional=file2.properties \ No newline at end of file diff --git a/libraries-apache-commons-2/src/test/resources/configuration/hierarchical.xml b/libraries-apache-commons-2/src/test/resources/configuration/hierarchical.xml new file mode 100644 index 0000000000..d4b965f577 --- /dev/null +++ b/libraries-apache-commons-2/src/test/resources/configuration/hierarchical.xml @@ -0,0 +1,14 @@ + + + + + + Pattern1 + Pattern2 + + + + + + + \ No newline at end of file diff --git a/libraries-apache-commons-2/src/test/resources/configuration/tenant-A.properties b/libraries-apache-commons-2/src/test/resources/configuration/tenant-A.properties new file mode 100644 index 0000000000..14de606980 --- /dev/null +++ b/libraries-apache-commons-2/src/test/resources/configuration/tenant-A.properties @@ -0,0 +1 @@ +name=Tenant A \ No newline at end of file diff --git a/libraries-apache-commons-2/src/test/resources/configuration/validation-sample.dtd b/libraries-apache-commons-2/src/test/resources/configuration/validation-sample.dtd new file mode 100644 index 0000000000..272bf5515d --- /dev/null +++ b/libraries-apache-commons-2/src/test/resources/configuration/validation-sample.dtd @@ -0,0 +1,13 @@ + + + + + + + +