From 5402e49b126ad3c5bc0e1305b95dd6d0c2fd58be Mon Sep 17 00:00:00 2001 From: Rikkarth <76500344+rikkarth@users.noreply.github.com> Date: Fri, 8 Dec 2023 17:34:14 +0000 Subject: [PATCH] PropertiesLoader, JavaDoc, commons-beanutils, README.md, maven.yml Update (#20) * Properties Exception Rearranged * Installed commons-beanutils, README.md Update * Improve and JavaDoc, PropertiesLoader.java - Fail scenario unit tests added for PropertiesLoaderTest.java * pom.xml Update * README.md Update * maven.yml Update --- .github/workflows/maven.yml | 50 +++++++ CHANGELOG.md | 13 ++ README.md | 87 +++++++++---- pom.xml | 23 +++- .../PropertiesGenerationException.java | 19 --- .../toolertools/props/PropertiesLoader.java | 122 +++++++++++++++--- .../PropertiesLoadingException.java | 4 +- .../props/PropertiesLoaderTest.java | 30 +++++ src/test/resources/test.properties | 3 +- 9 files changed, 284 insertions(+), 67 deletions(-) delete mode 100644 src/main/java/pt/codeforge/toolertools/internal/exceptions/PropertiesGenerationException.java rename src/main/java/pt/codeforge/toolertools/{internal/exceptions => props}/PropertiesLoadingException.java (73%) create mode 100644 src/test/java/pt/codeforge/toolertools/props/PropertiesLoaderTest.java diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index edc6181..9698183 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -17,6 +17,7 @@ on: jobs: test: + if: github.ref != 'refs/heads/main' runs-on: ubuntu-latest steps: - name: Checkout code @@ -29,3 +30,52 @@ jobs: cache: maven - name: Test with Maven run: mvn -B --update-snapshots clean test + + tag: + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + - name: Set up JDK 1.8 + uses: actions/setup-java@v3 + with: + java-version: '8' + distribution: 'corretto' + cache: maven + - name: Create Release + run: | + VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout) + echo "Creating release for version $VERSION" + git tag -a "v$VERSION" -m "Release $VERSION" + git push origin "$VERSION" + + publish: + if: github.event_name == 'push' && github.repository == 'refs/heads/main' + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + steps: + - uses: actions/checkout@v4 + - name: Set up Java for publishing to Maven Central Repository + uses: actions/setup-java@v3 + with: + java-version: '8' + distribution: 'corretto' + - name: Release Maven package + uses: samuelmeuli/action-maven-publish@v1.4.0 + with: + gpg_private_key: ${{ secrets.gpg_private_key }} + gpg_passphrase: ${{ secrets.gpg_passphrase }} + nexus_username: ${{ secrets.nexus_username }} + nexus_password: ${{ secrets.nexus_password }} + - name: Set up Java for publishing to GitHub Packages + uses: actions/setup-java@v3 + with: + java-version: '8' + distribution: 'corretto' + - name: Publish to GitHub Packages + run: mvn --batch-mode deploy + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/CHANGELOG.md b/CHANGELOG.md index d872631..8d9c085 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,19 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.0.7] - Dev + +### Added + +- commons-beanutils:commons-beanutils installed. +- PropertiesLoader JavaDoc + +### Changed + +- README.md +- pom.xml +- PropertiesLoader Improved + ## [0.0.6] - 07-12-2023 ### Added diff --git a/README.md b/README.md index 771881a..17cf8ec 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,11 @@ # Tooler-Tools +[![Maven Central](https://img.shields.io/maven-central/v/pt.codeforge/tooler-tools.svg)](https://mvnrepository.com/artifact/pt.codeforge/tooler-tools) +[![Java CI with Maven](https://github.com/rikkarth/tooler-tools/actions/workflows/maven.yml/badge.svg)](https://github.com/rikkarth/tooler-tools/actions/workflows/maven.yml) + Tooler-Tools: A versatile Java library for backend and CLI developers, offering a growing collection of tools to simplify your development tasks. -## Easy Integration - -[Sonatype Maven Central Repository][Sonatype Maven Central Repository Link] - -[GitHub Packages][GitHub Packages Link] - -[Sonatype Maven Central Repository Link]: https://central.sonatype.com/artifact/pt.codeforge/tooler-tools - -[GitHub Packages Link]: https://github.com/rikkarth/tooler-tools/packages/2005257 - ## Installation ``` @@ -29,31 +22,77 @@ simplify your development tasks. **EnvPathParser** parses and expands env path variables into file paths. -![EnvPathParserUseCase.png](docs/resources/EnvPathParserUseCase.png) +**PropertiesLoader** loads properties from various sources, such as files and system properties, +with support for environment variable expansion in file paths. ### Example - Get String From XPath +*XML Example* + +```xml + + + Test Value + + + + Item 1 + Item 2 + Item 3 + + ``` -String pages = getStringFromXPath("/root/path/to/element", doc); -``` -#### Possible outcomes: +*XmlHandler#getStringFromXPath use-case* + +```java +import pt.codeforge.toolertools.xml.XmlHandler; + +class TestClass { -1. `pages` is never null; -2. `pages` can be empty if value can't be found; -3. `pages` will return value. + @Test + void test() { + Document doc = XmlHandler.getOptionalDomFromFile(new File(input)).orElseThrow(IllegalStateException::new); + String textElement = XmlHandler.getStringFromXPath("/root/test-element/text()", doc); + + System.out.println(textElement); + } +} ``` -String pages = getStringFromXPath("/root/path/to/various-elements/text()", doc) // Returns First Element; -String pages = getStringFromXPath("/root/path/to/various-elements[1]/text()", doc) // Returns First Element; -String pages = getStringFromXPath("/root/path/to/various-elements[2]/text()", doc) // Returns Second Element; -String pages = getStringFromXPath("/root/path/to/various-elements[3]/text()", doc) // Returns Third Element; + +*Expected Output* + +```text +Test Value ``` -### Example - Get NodeList From XPath +*Other XPath Applications* + +```java +String nesteElement = XmlHandler.getStringFromXPath("/root/element-group/nested-element/text()",doc) // Returns First Element; +String nesteElement1 = XmlHandler.getStringFromXPath("/root/element-group/nested-element[1]/text()",doc) // Returns First Element; +String nesteElement2 = XmlHandler.getStringFromXPath("/root/element-group/nested-element[2]/text()",doc) // Returns Second Element; +String nesteElement3 = XmlHandler.getStringFromXPath("/root/element-group/nested-element[3]/text()",doc) // Returns Third Element; ``` -NodeList elements = getStringFromXPath("/root/path/to/various-elements", doc); -elements.getLength() // returns 0 if nothing found, and 'n' if something found. +### Example - Get NodeList From XPath +Returns 0 nodes if nothing found, and 'n' nodes if any found. +```java +import pt.codeforge.toolertools.xml.XmlHandler; + +class TestClass() { + + void test() { + NodeList elements = XmlHandler.getNodeListFromXPath("/root/element-group", doc); + + System.out.println(elements.getLength()); + } +} ``` +*Expected output* + +``` +3 +``` diff --git a/pom.xml b/pom.xml index ec996b9..ed53d83 100644 --- a/pom.xml +++ b/pom.xml @@ -1,10 +1,12 @@ - + 4.0.0 pt.codeforge tooler-tools - 0.0.6 + 0.0.7 jar tooler-tools Versatile library for backend and CLI developers, offers a growing collection of @@ -33,8 +35,8 @@ scm:git:git://github.com/rikkarth/tooler-tools.git scm:git:git@github.com:rikkarth/tooler-tools.git http://github.com/rikkarth/tooler-tools/tree/main - tooler-tools-0.0.6 - + ${project.artifactId}-${project.version} + @@ -53,6 +55,19 @@ 2.9.0 + + + commons-beanutils + commons-beanutils + 1.9.4 + + + commons-collections + commons-collections + + + + org.junit.jupiter diff --git a/src/main/java/pt/codeforge/toolertools/internal/exceptions/PropertiesGenerationException.java b/src/main/java/pt/codeforge/toolertools/internal/exceptions/PropertiesGenerationException.java deleted file mode 100644 index a3688c0..0000000 --- a/src/main/java/pt/codeforge/toolertools/internal/exceptions/PropertiesGenerationException.java +++ /dev/null @@ -1,19 +0,0 @@ -package pt.codeforge.toolertools.internal.exceptions; - -public class PropertiesGenerationException extends Exception { - - public PropertiesGenerationException(String message, Throwable cause) { - super(message, cause); - } - - public PropertiesGenerationException(String message) { - super(message); - } - - public PropertiesGenerationException(Throwable cause) { - super(cause); - } - - public PropertiesGenerationException() { - } -} diff --git a/src/main/java/pt/codeforge/toolertools/props/PropertiesLoader.java b/src/main/java/pt/codeforge/toolertools/props/PropertiesLoader.java index 97f59e2..fd3fd6c 100644 --- a/src/main/java/pt/codeforge/toolertools/props/PropertiesLoader.java +++ b/src/main/java/pt/codeforge/toolertools/props/PropertiesLoader.java @@ -1,47 +1,111 @@ package pt.codeforge.toolertools.props; +import java.io.File; +import java.nio.file.Path; import java.util.Iterator; import java.util.Optional; import java.util.Properties; import org.apache.commons.configuration2.Configuration; import org.apache.commons.configuration2.builder.fluent.Configurations; import org.apache.commons.configuration2.ex.ConfigurationException; -import pt.codeforge.toolertools.internal.exceptions.PropertiesGenerationException; -import pt.codeforge.toolertools.internal.exceptions.PropertiesLoadingException; import pt.codeforge.toolertools.pathfinder.EnvPathParser; +/** + * Utility class for loading properties from various sources, such as files and system properties, with support for + * environment variable expansion in file paths. + * + *

Instances of this class provide methods to load properties based on different inputs, including + * property names, paths, {@code java.nio.file.Path}, and {@code java.io.File}. + * + *

Environment variable placeholders in file paths are automatically expanded using the {@link EnvPathParser}. + * + * @see EnvPathParser + * @see PropertiesLoader#loadFromPropertyName(String) + * @see PropertiesLoader#loadFromPath(String) + * @see PropertiesLoader#loadFromPath(Path) + * @see PropertiesLoader#loadFromFile(File) + */ public class PropertiesLoader { - public static PropertiesLoader createPropertiesLoader() { - return new PropertiesLoader(); + private PropertiesLoader() { + throw new AssertionError("PropertiesLoader should not be instantiated."); } - public Properties loadProperties(String propName) throws PropertiesGenerationException { + /** + * Loads properties from the specified property name, expanding environment variable placeholders in the associated + * file path. + * + * @param propName The name of the property. Must not be null. + * @return The loaded properties. + * @throws PropertiesLoadingException If an error occurs during loading. + * @see EnvPathParser#getEnvPath(String) + */ + public static Properties loadFromPropertyName(String propName) { - String filePath = this.getOptionalFilePath(propName).orElseThrow( + String propertiesFilePath = getOptionalPropertiesFilePath(propName).orElseThrow( () -> new PropertiesLoadingException(getPropertiesLoadingErrorMsg(propName))); - String propsPath = EnvPathParser.getEnvPath(filePath); + String propsPath = EnvPathParser.getEnvPath(propertiesFilePath); - return this.getOptionalProperties(propsPath).orElseThrow( - () -> new PropertiesGenerationException(getInvalidPathToPropErrorMsg(propName, propsPath))); + return getOptionalProperties(propsPath).orElseThrow( + () -> new PropertiesLoadingException(getInvalidPathToPropErrorMsg(propName, propsPath))); } - private String getInvalidPathToPropErrorMsg(String propName, String propsPath) { - return String.format("Invalid path to %s.properties. Path provided -> %s", propName, propsPath); + /** + * Loads properties from the specified path, expanding environment variable placeholders. + * + * @param path The path to the properties file. Must not be null. + * @return The loaded properties. + * @throws PropertiesLoadingException If an error occurs during loading. + * @see EnvPathParser#getEnvPath(String) + */ + public static Properties loadFromPath(String path) { + + String propsPath = EnvPathParser.getEnvPath(path); + + return getOptionalProperties(propsPath).orElseThrow( + () -> new PropertiesLoadingException(getInvalidPathToPropErrorMsg(propsPath))); } - private String getPropertiesLoadingErrorMsg(String propName) { - return String.format("Error loading %s.properties.", propName); + /** + * Loads properties from the specified {@code java.nio.file.Path}, expanding environment variable placeholders. + * + * @param path The {@code java.nio.file.Path} to the properties file. Must not be null. + * @return The loaded properties. + * @throws PropertiesLoadingException If an error occurs during loading. + * @see EnvPathParser#getEnvPath(String) + */ + public static Properties loadFromPath(Path path) { + + String propsPath = EnvPathParser.getEnvPath(path.toString()); + + return getOptionalProperties(propsPath).orElseThrow( + () -> new PropertiesLoadingException(getInvalidPathToPropErrorMsg(propsPath))); + } + + /** + * Loads properties from the specified {@code java.io.File}, expanding environment variable placeholders. + * + * @param file The {@code java.io.File} representing the properties file. Must not be null. + * @return The loaded properties. + * @throws PropertiesLoadingException If an error occurs during loading. + * @see EnvPathParser#getEnvPath(String) + */ + public static Properties loadFromFile(File file) { + + String propsPath = EnvPathParser.getEnvPath(file.getAbsolutePath()); + + return getOptionalProperties(propsPath).orElseThrow( + () -> new PropertiesLoadingException(getInvalidPathToPropErrorMsg(propsPath))); } - private Optional getOptionalProperties(String filePath) { + private static Optional getOptionalProperties(String filePath) { try { Configurations configs = new Configurations(); Configuration config = configs.properties(filePath); Properties properties = new Properties(); Iterator keys = config.getKeys(); - keys.forEachRemaining((key) -> { + keys.forEachRemaining(key -> { String value = config.getString(key); properties.setProperty(key, value); }); @@ -51,8 +115,32 @@ private Optional getOptionalProperties(String filePath) { } } - private Optional getOptionalFilePath(String propName) { - return Optional.ofNullable(System.getProperty(propName)); + private static Optional getOptionalPropertiesFilePath(String propName) { + try { + return Optional.ofNullable(System.getProperty(propName)); + } catch (NullPointerException | IllegalArgumentException e) { + return Optional.empty(); + } + } + + private static String getInvalidPathToPropErrorMsg(String propName, String path) { + return String.format("Invalid path to %s.properties. Path provided -> %s", propName, path); + } + + private static String getInvalidPathToPropErrorMsg(String path) { + return String.format("Invalid path provided. Path provided -> %s", path); + } + + private static String getPropertiesLoadingErrorMsg(String propName) { + if (propName == null) { + return "Error loading properties. Key can't be null."; + } + + if (propName.isEmpty()) { + return "Error loading properties. Key can't be empty."; + } + + return String.format("Error loading %s.properties.", propName); } } diff --git a/src/main/java/pt/codeforge/toolertools/internal/exceptions/PropertiesLoadingException.java b/src/main/java/pt/codeforge/toolertools/props/PropertiesLoadingException.java similarity index 73% rename from src/main/java/pt/codeforge/toolertools/internal/exceptions/PropertiesLoadingException.java rename to src/main/java/pt/codeforge/toolertools/props/PropertiesLoadingException.java index 16cc883..17eb6cc 100644 --- a/src/main/java/pt/codeforge/toolertools/internal/exceptions/PropertiesLoadingException.java +++ b/src/main/java/pt/codeforge/toolertools/props/PropertiesLoadingException.java @@ -1,6 +1,6 @@ -package pt.codeforge.toolertools.internal.exceptions; +package pt.codeforge.toolertools.props; -public class PropertiesLoadingException extends RuntimeException { +class PropertiesLoadingException extends RuntimeException { public PropertiesLoadingException(String message, Throwable cause) { super(message, cause); diff --git a/src/test/java/pt/codeforge/toolertools/props/PropertiesLoaderTest.java b/src/test/java/pt/codeforge/toolertools/props/PropertiesLoaderTest.java new file mode 100644 index 0000000..32c2c7d --- /dev/null +++ b/src/test/java/pt/codeforge/toolertools/props/PropertiesLoaderTest.java @@ -0,0 +1,30 @@ +package pt.codeforge.toolertools.props; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +class PropertiesLoaderTest { + + @BeforeAll + static void setup() { + System.setProperty("test", "src/test/resources/test.properties" + ); + } + + @Test + void givenWrongInput_testLoadFromPropertyName_shouldThrowPropertiesLoadingException() { + assertThrows(PropertiesLoadingException.class, () -> PropertiesLoader.loadFromPropertyName("wrong")); + } + + @Test + void givenEmptyInput_testLoadFromPropertyName_shouldThrowPropertiesLoadingException() { + assertThrows(PropertiesLoadingException.class, () -> PropertiesLoader.loadFromPropertyName("")); + } + + @Test + void givenNullInput_testLoadFromPropertyName_shouldThrowPropertiesLoadingException() { + assertThrows(PropertiesLoadingException.class, () -> PropertiesLoader.loadFromPropertyName(null)); + } +} diff --git a/src/test/resources/test.properties b/src/test/resources/test.properties index 1935ecc..09ea3a1 100644 --- a/src/test/resources/test.properties +++ b/src/test/resources/test.properties @@ -1,4 +1,5 @@ -HOME=$HOME +HOME=${env:HOME} +HOMEUSR=${env:HOMEDRIVE}${env:HOMEPATH} testVariable=testVariable_test fromVariable=${testVariable} comboVariable=${HOME}/${fromVariable}