From 54db40cc1035efed32d93b26ac08032743784c08 Mon Sep 17 00:00:00 2001 From: Swetank Mohanty Date: Tue, 1 Apr 2025 23:48:57 +0530 Subject: [PATCH 01/12] core: Project restructured into single module --- .../.editorconfig => .editorconfig | 0 .github/workflows/maven-release.yml | 91 ++++ .../annotations/.gitkeep => .mvn/jvm.config | 0 .../.mvn => .mvn}/maven.config | 0 .../wrapper/maven-wrapper.properties | 0 README.md | 19 +- changelog.mustache | 12 + pom-default.xml | 291 ------------ pom.xml | 298 +++++++++++++ primekit-essentials/.gitignore | 11 - primekit-essentials/pom.xml | 344 -------------- .../essentials/common/CounterNode.java | 0 .../essentials/common/GenericConstants.java | 0 .../primekit/essentials/common/ListNode.java | 0 .../primekit/essentials/common/TreeNode.java | 0 .../primekit/essentials/common/YearWeek.java | 0 .../common/converter/Converter.java | 0 .../converter/StringToBooleanConverter.java | 0 .../converter/StringToDateConverter.java | 0 .../converter/StringToDoubleConverter.java | 0 .../converter/StringToHashMapConverter.java | 0 .../converter/StringToIntegerConverter.java | 0 .../converter/StringToListConverter.java | 0 .../converter/StringToMapConverter.java | 0 .../essentials/common/enums/CryptoModes.java | 0 .../essentials/common/enums/FileTypes.java | 0 .../common/enums/HibernateDialects.java | 0 .../essentials/common/util/ArrayUtils.java | 0 .../common/util/BinaryTreeUtils.java | 0 .../essentials/common/util/ClassUtils.java | 0 .../common/util/CollectionUtils.java | 0 .../common/util/ConfigurationUtils.java | 0 .../essentials/common/util/CryptoUtils.java | 0 .../essentials/common/util/DateUtils.java | 0 .../essentials/common/util/EOLUtils.java | 0 .../essentials/common/util/FileUtils.java | 0 .../common/util/HibernateUtils.java | 0 .../essentials/common/util/LDAPUtils.java | 0 .../essentials/common/util/MathUtils.java | 0 .../essentials/common/util/NetworkUtils.java | 0 .../essentials/common/util/NumberUtils.java | 0 .../common/util/PostgreSQLUtils.java | 0 .../essentials/common/util/StringUtils.java | 0 .../essentials/common/util/SystemUtils.java | 0 .../essentials/core/annotations}/.gitkeep | 0 .../webmvc/AbstractBaseController.java | 0 .../generics/webmvc/AbstractBaseDTO.java | 0 .../generics/webmvc/AbstractBaseEntity.java | 0 .../webmvc/AbstractBaseRepository.java | 0 .../generics/webmvc/AbstractBaseService.java | 0 .../primekit/essentials/webclient/.gitkeep | 0 .../primekit/essentials/ArrayUtilsTest.java | 0 .../essentials/CollectionUtilsTests.java | 0 .../primekit/essentials/DateUtilsTest.java | 0 .../primekit/essentials/MathUtilsTests.java | 0 .../essentials/common/util/LDAPUtilsTest.java | 0 techstack.md | 159 ------- techstack.yml | 421 ------------------ 58 files changed, 403 insertions(+), 1243 deletions(-) rename primekit-essentials/.editorconfig => .editorconfig (100%) create mode 100644 .github/workflows/maven-release.yml rename primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/core/annotations/.gitkeep => .mvn/jvm.config (100%) rename {primekit-essentials/.mvn => .mvn}/maven.config (100%) rename {primekit-essentials/.mvn => .mvn}/wrapper/maven-wrapper.properties (100%) create mode 100644 changelog.mustache delete mode 100644 pom-default.xml create mode 100644 pom.xml delete mode 100644 primekit-essentials/.gitignore delete mode 100644 primekit-essentials/pom.xml rename {primekit-essentials/src => src}/main/java/com/shortthirdman/primekit/essentials/common/CounterNode.java (100%) rename {primekit-essentials/src => src}/main/java/com/shortthirdman/primekit/essentials/common/GenericConstants.java (100%) rename {primekit-essentials/src => src}/main/java/com/shortthirdman/primekit/essentials/common/ListNode.java (100%) rename {primekit-essentials/src => src}/main/java/com/shortthirdman/primekit/essentials/common/TreeNode.java (100%) rename {primekit-essentials/src => src}/main/java/com/shortthirdman/primekit/essentials/common/YearWeek.java (100%) rename {primekit-essentials/src => src}/main/java/com/shortthirdman/primekit/essentials/common/converter/Converter.java (100%) rename {primekit-essentials/src => src}/main/java/com/shortthirdman/primekit/essentials/common/converter/StringToBooleanConverter.java (100%) rename {primekit-essentials/src => src}/main/java/com/shortthirdman/primekit/essentials/common/converter/StringToDateConverter.java (100%) rename {primekit-essentials/src => src}/main/java/com/shortthirdman/primekit/essentials/common/converter/StringToDoubleConverter.java (100%) rename {primekit-essentials/src => src}/main/java/com/shortthirdman/primekit/essentials/common/converter/StringToHashMapConverter.java (100%) rename {primekit-essentials/src => src}/main/java/com/shortthirdman/primekit/essentials/common/converter/StringToIntegerConverter.java (100%) rename {primekit-essentials/src => src}/main/java/com/shortthirdman/primekit/essentials/common/converter/StringToListConverter.java (100%) rename {primekit-essentials/src => src}/main/java/com/shortthirdman/primekit/essentials/common/converter/StringToMapConverter.java (100%) rename {primekit-essentials/src => src}/main/java/com/shortthirdman/primekit/essentials/common/enums/CryptoModes.java (100%) rename {primekit-essentials/src => src}/main/java/com/shortthirdman/primekit/essentials/common/enums/FileTypes.java (100%) rename {primekit-essentials/src => src}/main/java/com/shortthirdman/primekit/essentials/common/enums/HibernateDialects.java (100%) rename {primekit-essentials/src => src}/main/java/com/shortthirdman/primekit/essentials/common/util/ArrayUtils.java (100%) rename {primekit-essentials/src => src}/main/java/com/shortthirdman/primekit/essentials/common/util/BinaryTreeUtils.java (100%) rename {primekit-essentials/src => src}/main/java/com/shortthirdman/primekit/essentials/common/util/ClassUtils.java (100%) rename {primekit-essentials/src => src}/main/java/com/shortthirdman/primekit/essentials/common/util/CollectionUtils.java (100%) rename {primekit-essentials/src => src}/main/java/com/shortthirdman/primekit/essentials/common/util/ConfigurationUtils.java (100%) rename {primekit-essentials/src => src}/main/java/com/shortthirdman/primekit/essentials/common/util/CryptoUtils.java (100%) rename {primekit-essentials/src => src}/main/java/com/shortthirdman/primekit/essentials/common/util/DateUtils.java (100%) rename {primekit-essentials/src => src}/main/java/com/shortthirdman/primekit/essentials/common/util/EOLUtils.java (100%) rename {primekit-essentials/src => src}/main/java/com/shortthirdman/primekit/essentials/common/util/FileUtils.java (100%) rename {primekit-essentials/src => src}/main/java/com/shortthirdman/primekit/essentials/common/util/HibernateUtils.java (100%) rename {primekit-essentials/src => src}/main/java/com/shortthirdman/primekit/essentials/common/util/LDAPUtils.java (100%) rename {primekit-essentials/src => src}/main/java/com/shortthirdman/primekit/essentials/common/util/MathUtils.java (100%) rename {primekit-essentials/src => src}/main/java/com/shortthirdman/primekit/essentials/common/util/NetworkUtils.java (100%) rename {primekit-essentials/src => src}/main/java/com/shortthirdman/primekit/essentials/common/util/NumberUtils.java (100%) rename {primekit-essentials/src => src}/main/java/com/shortthirdman/primekit/essentials/common/util/PostgreSQLUtils.java (100%) rename {primekit-essentials/src => src}/main/java/com/shortthirdman/primekit/essentials/common/util/StringUtils.java (100%) rename {primekit-essentials/src => src}/main/java/com/shortthirdman/primekit/essentials/common/util/SystemUtils.java (100%) rename {primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/webclient => src/main/java/com/shortthirdman/primekit/essentials/core/annotations}/.gitkeep (100%) rename {primekit-essentials/src => src}/main/java/com/shortthirdman/primekit/essentials/generics/webmvc/AbstractBaseController.java (100%) rename {primekit-essentials/src => src}/main/java/com/shortthirdman/primekit/essentials/generics/webmvc/AbstractBaseDTO.java (100%) rename {primekit-essentials/src => src}/main/java/com/shortthirdman/primekit/essentials/generics/webmvc/AbstractBaseEntity.java (100%) rename {primekit-essentials/src => src}/main/java/com/shortthirdman/primekit/essentials/generics/webmvc/AbstractBaseRepository.java (100%) rename {primekit-essentials/src => src}/main/java/com/shortthirdman/primekit/essentials/generics/webmvc/AbstractBaseService.java (100%) create mode 100644 src/main/java/com/shortthirdman/primekit/essentials/webclient/.gitkeep rename {primekit-essentials/src => src}/test/java/com/shortthirdman/primekit/essentials/ArrayUtilsTest.java (100%) rename {primekit-essentials/src => src}/test/java/com/shortthirdman/primekit/essentials/CollectionUtilsTests.java (100%) rename {primekit-essentials/src => src}/test/java/com/shortthirdman/primekit/essentials/DateUtilsTest.java (100%) rename {primekit-essentials/src => src}/test/java/com/shortthirdman/primekit/essentials/MathUtilsTests.java (100%) rename {primekit-essentials/src => src}/test/java/com/shortthirdman/primekit/essentials/common/util/LDAPUtilsTest.java (100%) delete mode 100644 techstack.md delete mode 100644 techstack.yml diff --git a/primekit-essentials/.editorconfig b/.editorconfig similarity index 100% rename from primekit-essentials/.editorconfig rename to .editorconfig diff --git a/.github/workflows/maven-release.yml b/.github/workflows/maven-release.yml new file mode 100644 index 0000000..c1abff8 --- /dev/null +++ b/.github/workflows/maven-release.yml @@ -0,0 +1,91 @@ +name: Maven Release + +on: + workflow_dispatch: + inputs: + releaseVersion: + description: 'Release version' + required: true + developmentVersion: + description: 'Next development version' + required: true + +jobs: + release: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + token: ${{ secrets.RELEASE_TOKEN }} + + - name: Set up JDK + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'temurin' + cache: maven + + - name: Configure Git user + run: | + git config user.email "actions@github.com" + git config user.name "GitHub Actions" + + - name: Generate Changelog + run: mvn git-changelog-maven-plugin:git-changelog + + - name: Commit Changelog + run: | + git add CHANGELOG.md + git commit -m "docs: update changelog for version ${{ github.event.inputs.releaseVersion }}" + git push origin main + + - name: Setup Maven settings.xml + uses: s4u/maven-settings-action@v3.0.0 + with: + servers: | + [{ + "id": "github", + "username": "${{ github.actor }}", + "password": "${{ secrets.RELEASE_TOKEN }}" + }] + + - name: Prepare Release + run: | + set -e + mvn release:prepare \ + -DreleaseVersion=${{ github.event.inputs.releaseVersion }} \ + -DdevelopmentVersion=${{ github.event.inputs.developmentVersion }} \ + -DtagNameFormat=v@{project.version} + + - name: Perform Release + run: mvn release:perform + + - name: Push changes + run: | + set -e + git push origin main + git push origin --tags + + - name: Get Changelog Entry + id: changelog + run: | + CHANGELOG_ENTRY=$(sed -n "/## ${GITHUB_REF#refs/tags/}/,/## /p" CHANGELOG.md | sed '$d') + echo "changelog<> $GITHUB_OUTPUT + echo "$CHANGELOG_ENTRY" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + + - name: Create GitHub Release + uses: softprops/action-gh-release@v1 + with: + tag_name: v${{ github.event.inputs.releaseVersion }} + name: Release v${{ github.event.inputs.releaseVersion }} + body: ${{ steps.changelog.outputs.changelog }} + files: | + target/*.jar + target/*.pom + draft: true + prerelease: false + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/core/annotations/.gitkeep b/.mvn/jvm.config similarity index 100% rename from primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/core/annotations/.gitkeep rename to .mvn/jvm.config diff --git a/primekit-essentials/.mvn/maven.config b/.mvn/maven.config similarity index 100% rename from primekit-essentials/.mvn/maven.config rename to .mvn/maven.config diff --git a/primekit-essentials/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties similarity index 100% rename from primekit-essentials/.mvn/wrapper/maven-wrapper.properties rename to .mvn/wrapper/maven-wrapper.properties diff --git a/README.md b/README.md index 4e8cf96..49cde6a 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,4 @@ -# PrimeKit Essentials - -[![StackShare](http://img.shields.io/badge/tech-stack-0690fa.svg?style=flat)](https://stackshare.io/shortthirdman-org/prime-kit) +# PrimeKit Welcome to PrimeKit Essentials, an innovative project designed to enhance your development toolkit and streamline your workflow. Whether you're a seasoned developer or just starting out, PrimeKit Essentials offers essential functionalities that empower your development journey. @@ -31,20 +29,6 @@ Your feedback and support are invaluable to us. Let's empower developers togethe ![GitHub closed issues](https://img.shields.io/github/issues-closed/shortthirdman-org/PrimeKit) ![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/shortthirdman-org/PrimeKit/maven.yml?branch=main) -## Tech Stack - -> shortthirdman-org/PrimeKit is built on the following main stack: - -- Java [Java](https://www.java.com) – Languages -- Spring Framework [Spring Framework](https://spring.io/projects/spring-framework) – Frameworks (Full Stack) -- PostgreSQL [PostgreSQL](http://www.postgresql.org/) – Databases -- Spring Data [Spring Data](https://spring.io/projects/spring-data) – Database Tools -- GitHub Actions [GitHub Actions](https://github.com/features/actions) – Continuous Integration -- JUnit [JUnit](http://junit.org/) – Testing Frameworks - -Full tech stack [here](/techstack.md) - - ## Community Resources * [Release a Java Module with JReleaser to Maven Central with GitHub Actions](https://foojay.io/today/how-to-release-a-java-module-with-jreleaser-to-maven-central-with-github-actions/) @@ -60,3 +44,4 @@ For further reference, please consider the following sections: * [Create an OCI image](https://docs.spring.io/spring-boot/docs/3.2.6/maven-plugin/reference/html/#build-image) * [Spring Shell](https://spring.io/projects/spring-shell) +[Master Java Releases with GitHub Actions and Maven Release Plugin](https://vrnsky.medium.com/master-java-releases-with-github-actions-and-maven-release-plugin-0a6fce46a2d7) \ No newline at end of file diff --git a/changelog.mustache b/changelog.mustache new file mode 100644 index 0000000..5dbca82 --- /dev/null +++ b/changelog.mustache @@ -0,0 +1,12 @@ +# Changelog + +{{#tags}} +## {{name}} +{{#commits}} +* {{{messageTitle}}} +{{#messageBodyItems}} + * {{.}} +{{/messageBodyItems}} +{{/commits}} + +{{/tags}} \ No newline at end of file diff --git a/pom-default.xml b/pom-default.xml deleted file mode 100644 index 33ffa10..0000000 --- a/pom-default.xml +++ /dev/null @@ -1,291 +0,0 @@ - - - - 4.0.0 - - com.shortthirdman - sharedlibs - 0.0.1-SNAPSHOT - sharedlibs - https://www.github.com/shortthirdman-org/sharedlibs - - - UTF-8 - 1.8 - 1.8 - 1.8 - 3.19.0 - 5.6.10.Final - - - - - primary - Swetank Mohanty - swetank.mohanty@outlook.com - IBM India - UTC+530 - - Application Developer - - - - - - - Swetank Mohanty - swetank.mohanty@outlook.com - IBM India - UTC+530 - - - - - - The Apache License, Version 2.0 - http://www.apache.org/licenses/LICENSE-2.0.txt - - - - - - - - junit - junit - 4.13.2 - test - - - commons-codec - commons-codec - 1.15 - - - commons-io - commons-io - 2.11.0 - - - org.hibernate - hibernate-core - ${hibernate.version} - - - org.apache.commons - commons-lang3 - 3.12.0 - - - org.assertj - assertj-core - ${assertj.version} - test - - - - - - release - - - performRelease - false - - - - - - - org.apache.maven.plugins - maven-source-plugin - 3.2.1 - - - attach-sources - install - - jar-no-fork - - - - - - - - - - reporting - - - - - - org.apache.maven.plugins - maven-project-info-reports-plugin - 3.4.2 - - - - - - - - - - - - org.sonatype.plugins - nexus-staging-maven-plugin - 1.6.7 - true - - ossrh - https://s01.oss.sonatype.org/ - true - - - - maven-compiler-plugin - 3.8.0 - - UTF-8 - 1.8 - 1.8 - - - - org.apache.maven.plugins - maven-jar-plugin - 3.3.0 - - true - true - - - - maven-surefire-plugin - 2.22.1 - - true - - - - org.apache.maven.surefire - surefire-junit47 - 3.0.0 - - - - - maven-deploy-plugin - 2.8.2 - - - org.jacoco - jacoco-maven-plugin - 0.8.8 - - - - prepare-agent - - - - jacoco-report - test - - report - - - - jacoco-check - - check - - - - - PACKAGE - - - LINE - COVEREDRATIO - 0.65 - - - - - - - - - - - - diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..d6a98b0 --- /dev/null +++ b/pom.xml @@ -0,0 +1,298 @@ + + + 4.0.0 + + com.shortthirdman.primekit + primekit-essentials + 1.0-SNAPSHOT + PrimeKit Essentials + https://www.github.com/shortthirdman-org/PrimeKit + 2025 + + + 1.8 + UTF-8 + 1.8 + 1.8 + 21 + 1.18.32 + 6.2.5 + 2.15.4 + 4.0.2 + 5.6.10.Final + 5.11.0 + 3.19.0 + + + + + author + Swetank Mohanty + swetank.mohanty@outlook.com + ShortThirdMan + UTC+530 + + Product Owner + + + + + + + Swetank Mohanty + swetank.mohanty@outlook.com + ShortThirdMan + UTC+530 + + + + + + The Apache License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + + + + + + github + GitHub Packages + https://maven.pkg.github.com/${github.repository} + + + + + scm:git:https://github.com/shortthirdman/PrimeKit.git + HEAD + + + + + + org.springframework + spring-framework-bom + ${springframework.version} + pom + import + + + org.junit + junit-bom + ${junit.version} + pom + import + + + + + + + jakarta.annotation + jakarta.annotation-api + 3.0.0 + + + jakarta.xml.bind + jakarta.xml.bind-api + ${jakarta.xml-bind.version} + + + org.springframework + spring-core + ${springframework.version} + + + org.springframework + spring-beans + ${springframework.version} + + + org.springframework + spring-webmvc + ${springframework.version} + + + org.springframework + spring-aop + ${springframework.version} + + + org.springframework + spring-context-support + ${springframework.version} + + + org.springframework.security + spring-security-core + ${springframework.version} + + + org.springframework + spring-context + ${springframework.version} + + + org.springframework + spring-web + ${springframework.version} + + + org.springframework + spring-jpa + 2.0.8 + + + commons-codec + commons-codec + 1.15 + + + commons-io + commons-io + 2.11.0 + + + org.hibernate + hibernate-core + ${hibernate.version} + + + org.hibernate.common + hibernate-commons-annotations + 5.1.2.Final + + + jakarta.persistence + jakarta.persistence-api + 3.2.0-M2 + + + com.fasterxml.jackson.core + jackson-core + ${fasterxml-jackson.version} + + + com.fasterxml.jackson.core + jackson-annotations + ${fasterxml-jackson.version} + + + org.apache.commons + commons-lang3 + 3.12.0 + + + org.projectlombok + lombok + ${lombok.version} + true + + + org.assertj + assertj-core + ${assertj.version} + test + + + org.junit.jupiter + junit-jupiter-api + test + + + + org.junit.jupiter + junit-jupiter-params + test + + + + + primekit-essentials-${project.version} + + + + maven-resources-plugin + 3.3.1 + + + maven-compiler-plugin + 3.13.0 + + false + UTF-8 + ${java.version} + ${java.version} + + + + maven-surefire-plugin + 3.3.0 + + true + + + + maven-jar-plugin + 3.4.2 + + true + true + + + + maven-deploy-plugin + 3.1.2 + + + org.apache.maven.plugins + maven-source-plugin + 3.2.1 + + + attach-sources + install + + jar-no-fork + + + + + + org.apache.maven.plugins + maven-release-plugin + 3.0.1 + + v@{project.version} + + pom.xml + + false + true + deploy + + + + se.bjurr.gitchangelog + git-changelog-maven-plugin + 2.2.0 + + + GenerateGitChangelog + generate-sources + + git-changelog + + + changelog.mustache + -([^-]+?)$ + CHANGELOG.md + false + + + + + + + + diff --git a/primekit-essentials/.gitignore b/primekit-essentials/.gitignore deleted file mode 100644 index 0e13eeb..0000000 --- a/primekit-essentials/.gitignore +++ /dev/null @@ -1,11 +0,0 @@ -target/ -pom.xml.tag -pom.xml.releaseBackup -pom.xml.versionsBackup -pom.xml.next -release.properties -dependency-reduced-pom.xml -buildNumber.properties -.mvn/timing.properties -# https://github.com/takari/maven-wrapper#usage-without-binary-jar -.mvn/wrapper/maven-wrapper.jar diff --git a/primekit-essentials/pom.xml b/primekit-essentials/pom.xml deleted file mode 100644 index 1be52f2..0000000 --- a/primekit-essentials/pom.xml +++ /dev/null @@ -1,344 +0,0 @@ - - - - 4.0.0 - - com.shortthirdman - primekit-essentials - 1.0.0-SNAPSHOT - primekit-essentials - jar - PrimeKit Essentials - https://www.github.com/shortthirdman-org/PrimeKit - - - UTF-8 - 21 - ${java.version} - ${java.version} - ${java.version} - 1.18.30 - 6.1.8 - 3.2.5 - 2.15.4 - 4.0.2 - 3.25.3 - 42.7.3 - 5.10.2 - 0.8.9 - - - - - primary - Swetank Mohanty - swetank.mohanty@outlook.com - ShortThirdMan - UTC+530 - - Application Developer - Product Owner - - - - - - - Swetank Mohanty - swetank.mohanty@outlook.com - ShortThirdMan - UTC+530 - - - - - - jakarta.annotation - jakarta.annotation-api - 3.0.0 - - - jakarta.xml.bind - jakarta.xml.bind-api - ${jakarta.xml-bind.version} - - - commons-codec - commons-codec - 1.15 - - - commons-io - commons-io - 2.11.0 - - - org.apache.commons - commons-lang3 - 3.12.0 - - - org.projectlombok - lombok - ${lombok.version} - - - org.springframework - spring-core - ${springframework.version} - - - org.springframework - spring-beans - ${springframework.version} - - - org.springframework - spring-webmvc - ${springframework.version} - - - org.springframework - spring-aop - ${springframework.version} - - - org.springframework - spring-context-support - ${springframework.version} - - - org.springframework.security - spring-security-core - ${springframework.version} - - - org.springframework - spring-context - ${springframework.version} - - - org.springframework - spring-web - ${springframework.version} - - - org.springframework - spring-jpa - 2.0.8 - - - org.springframework.data - spring-data-jpa - ${spring-data.version} - - - org.springframework.data - spring-data-commons - ${spring-data.version} - - - org.hibernate.common - hibernate-commons-annotations - 5.1.2.Final - - - org.hibernate - hibernate-core - 5.6.15.Final - - - jakarta.persistence - jakarta.persistence-api - 3.2.0-M2 - - - com.fasterxml.jackson.core - jackson-core - ${fasterxml-jackson.version} - - - com.fasterxml.jackson.core - jackson-annotations - ${fasterxml-jackson.version} - - - - org.postgresql - postgresql - ${postgresql.version} - provided - - - - org.junit.jupiter - junit-jupiter-api - ${junit-jupiter.version} - test - - - org.junit.jupiter - junit-jupiter-engine - ${junit-jupiter.version} - test - - - org.junit.jupiter - junit-jupiter-params - ${junit-jupiter.version} - test - - - org.junit.platform - junit-platform-runner - 1.10.2 - test - - - org.junit.platform - junit-platform-suite-engine - 1.9.1 - test - - - - - - - maven-resources-plugin - 3.0.2 - - - maven-compiler-plugin - 3.13.0 - - false - UTF-8 - ${java.version} - ${java.version} - - - - maven-surefire-plugin - 3.2.5 - - - me.fabriciorby - maven-surefire-junit5-tree-reporter - 1.2.1 - - - - 1 - ${project.build.sourceEncoding} - brief - - - junit.jupiter.conditions.deactivate = * - junit.jupiter.extensions.autodetection.enabled = true - junit.jupiter.testinstance.lifecycle.default = per_class - junit.jupiter.execution.parallel.enabled = true - - - - false - 3.0 - false - true - true - true - - - false - UTF-8 - false - - - false - false - true - true - - - - - maven-jar-plugin - 3.0.2 - - - maven-deploy-plugin - 2.8.2 - - - maven-project-info-reports-plugin - 3.0.0 - - - org.jacoco - jacoco-maven-plugin - ${jacoco.version} - - ${project.build.directory}/jacoco.exec - ${project.reporting.outputDirectory}/jacocoHtml - 140 - ${project.name} ${project.version} - - - - default-prepare-agent - - prepare-agent - - initialize - - - default-report - - report - - test - - - jacoco-check - test - - check - - - - - PACKAGE - - - LINE - COVEREDRATIO - 0.6 - - - INSTRUCTION - COVEREDRATIO - 65% - - - - - - - - - - - - - diff --git a/primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/CounterNode.java b/src/main/java/com/shortthirdman/primekit/essentials/common/CounterNode.java similarity index 100% rename from primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/CounterNode.java rename to src/main/java/com/shortthirdman/primekit/essentials/common/CounterNode.java diff --git a/primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/GenericConstants.java b/src/main/java/com/shortthirdman/primekit/essentials/common/GenericConstants.java similarity index 100% rename from primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/GenericConstants.java rename to src/main/java/com/shortthirdman/primekit/essentials/common/GenericConstants.java diff --git a/primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/ListNode.java b/src/main/java/com/shortthirdman/primekit/essentials/common/ListNode.java similarity index 100% rename from primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/ListNode.java rename to src/main/java/com/shortthirdman/primekit/essentials/common/ListNode.java diff --git a/primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/TreeNode.java b/src/main/java/com/shortthirdman/primekit/essentials/common/TreeNode.java similarity index 100% rename from primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/TreeNode.java rename to src/main/java/com/shortthirdman/primekit/essentials/common/TreeNode.java diff --git a/primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/YearWeek.java b/src/main/java/com/shortthirdman/primekit/essentials/common/YearWeek.java similarity index 100% rename from primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/YearWeek.java rename to src/main/java/com/shortthirdman/primekit/essentials/common/YearWeek.java diff --git a/primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/converter/Converter.java b/src/main/java/com/shortthirdman/primekit/essentials/common/converter/Converter.java similarity index 100% rename from primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/converter/Converter.java rename to src/main/java/com/shortthirdman/primekit/essentials/common/converter/Converter.java diff --git a/primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/converter/StringToBooleanConverter.java b/src/main/java/com/shortthirdman/primekit/essentials/common/converter/StringToBooleanConverter.java similarity index 100% rename from primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/converter/StringToBooleanConverter.java rename to src/main/java/com/shortthirdman/primekit/essentials/common/converter/StringToBooleanConverter.java diff --git a/primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/converter/StringToDateConverter.java b/src/main/java/com/shortthirdman/primekit/essentials/common/converter/StringToDateConverter.java similarity index 100% rename from primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/converter/StringToDateConverter.java rename to src/main/java/com/shortthirdman/primekit/essentials/common/converter/StringToDateConverter.java diff --git a/primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/converter/StringToDoubleConverter.java b/src/main/java/com/shortthirdman/primekit/essentials/common/converter/StringToDoubleConverter.java similarity index 100% rename from primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/converter/StringToDoubleConverter.java rename to src/main/java/com/shortthirdman/primekit/essentials/common/converter/StringToDoubleConverter.java diff --git a/primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/converter/StringToHashMapConverter.java b/src/main/java/com/shortthirdman/primekit/essentials/common/converter/StringToHashMapConverter.java similarity index 100% rename from primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/converter/StringToHashMapConverter.java rename to src/main/java/com/shortthirdman/primekit/essentials/common/converter/StringToHashMapConverter.java diff --git a/primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/converter/StringToIntegerConverter.java b/src/main/java/com/shortthirdman/primekit/essentials/common/converter/StringToIntegerConverter.java similarity index 100% rename from primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/converter/StringToIntegerConverter.java rename to src/main/java/com/shortthirdman/primekit/essentials/common/converter/StringToIntegerConverter.java diff --git a/primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/converter/StringToListConverter.java b/src/main/java/com/shortthirdman/primekit/essentials/common/converter/StringToListConverter.java similarity index 100% rename from primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/converter/StringToListConverter.java rename to src/main/java/com/shortthirdman/primekit/essentials/common/converter/StringToListConverter.java diff --git a/primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/converter/StringToMapConverter.java b/src/main/java/com/shortthirdman/primekit/essentials/common/converter/StringToMapConverter.java similarity index 100% rename from primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/converter/StringToMapConverter.java rename to src/main/java/com/shortthirdman/primekit/essentials/common/converter/StringToMapConverter.java diff --git a/primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/enums/CryptoModes.java b/src/main/java/com/shortthirdman/primekit/essentials/common/enums/CryptoModes.java similarity index 100% rename from primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/enums/CryptoModes.java rename to src/main/java/com/shortthirdman/primekit/essentials/common/enums/CryptoModes.java diff --git a/primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/enums/FileTypes.java b/src/main/java/com/shortthirdman/primekit/essentials/common/enums/FileTypes.java similarity index 100% rename from primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/enums/FileTypes.java rename to src/main/java/com/shortthirdman/primekit/essentials/common/enums/FileTypes.java diff --git a/primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/enums/HibernateDialects.java b/src/main/java/com/shortthirdman/primekit/essentials/common/enums/HibernateDialects.java similarity index 100% rename from primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/enums/HibernateDialects.java rename to src/main/java/com/shortthirdman/primekit/essentials/common/enums/HibernateDialects.java diff --git a/primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/util/ArrayUtils.java b/src/main/java/com/shortthirdman/primekit/essentials/common/util/ArrayUtils.java similarity index 100% rename from primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/util/ArrayUtils.java rename to src/main/java/com/shortthirdman/primekit/essentials/common/util/ArrayUtils.java diff --git a/primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/util/BinaryTreeUtils.java b/src/main/java/com/shortthirdman/primekit/essentials/common/util/BinaryTreeUtils.java similarity index 100% rename from primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/util/BinaryTreeUtils.java rename to src/main/java/com/shortthirdman/primekit/essentials/common/util/BinaryTreeUtils.java diff --git a/primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/util/ClassUtils.java b/src/main/java/com/shortthirdman/primekit/essentials/common/util/ClassUtils.java similarity index 100% rename from primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/util/ClassUtils.java rename to src/main/java/com/shortthirdman/primekit/essentials/common/util/ClassUtils.java diff --git a/primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/util/CollectionUtils.java b/src/main/java/com/shortthirdman/primekit/essentials/common/util/CollectionUtils.java similarity index 100% rename from primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/util/CollectionUtils.java rename to src/main/java/com/shortthirdman/primekit/essentials/common/util/CollectionUtils.java diff --git a/primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/util/ConfigurationUtils.java b/src/main/java/com/shortthirdman/primekit/essentials/common/util/ConfigurationUtils.java similarity index 100% rename from primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/util/ConfigurationUtils.java rename to src/main/java/com/shortthirdman/primekit/essentials/common/util/ConfigurationUtils.java diff --git a/primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/util/CryptoUtils.java b/src/main/java/com/shortthirdman/primekit/essentials/common/util/CryptoUtils.java similarity index 100% rename from primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/util/CryptoUtils.java rename to src/main/java/com/shortthirdman/primekit/essentials/common/util/CryptoUtils.java diff --git a/primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/util/DateUtils.java b/src/main/java/com/shortthirdman/primekit/essentials/common/util/DateUtils.java similarity index 100% rename from primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/util/DateUtils.java rename to src/main/java/com/shortthirdman/primekit/essentials/common/util/DateUtils.java diff --git a/primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/util/EOLUtils.java b/src/main/java/com/shortthirdman/primekit/essentials/common/util/EOLUtils.java similarity index 100% rename from primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/util/EOLUtils.java rename to src/main/java/com/shortthirdman/primekit/essentials/common/util/EOLUtils.java diff --git a/primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/util/FileUtils.java b/src/main/java/com/shortthirdman/primekit/essentials/common/util/FileUtils.java similarity index 100% rename from primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/util/FileUtils.java rename to src/main/java/com/shortthirdman/primekit/essentials/common/util/FileUtils.java diff --git a/primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/util/HibernateUtils.java b/src/main/java/com/shortthirdman/primekit/essentials/common/util/HibernateUtils.java similarity index 100% rename from primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/util/HibernateUtils.java rename to src/main/java/com/shortthirdman/primekit/essentials/common/util/HibernateUtils.java diff --git a/primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/util/LDAPUtils.java b/src/main/java/com/shortthirdman/primekit/essentials/common/util/LDAPUtils.java similarity index 100% rename from primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/util/LDAPUtils.java rename to src/main/java/com/shortthirdman/primekit/essentials/common/util/LDAPUtils.java diff --git a/primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/util/MathUtils.java b/src/main/java/com/shortthirdman/primekit/essentials/common/util/MathUtils.java similarity index 100% rename from primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/util/MathUtils.java rename to src/main/java/com/shortthirdman/primekit/essentials/common/util/MathUtils.java diff --git a/primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/util/NetworkUtils.java b/src/main/java/com/shortthirdman/primekit/essentials/common/util/NetworkUtils.java similarity index 100% rename from primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/util/NetworkUtils.java rename to src/main/java/com/shortthirdman/primekit/essentials/common/util/NetworkUtils.java diff --git a/primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/util/NumberUtils.java b/src/main/java/com/shortthirdman/primekit/essentials/common/util/NumberUtils.java similarity index 100% rename from primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/util/NumberUtils.java rename to src/main/java/com/shortthirdman/primekit/essentials/common/util/NumberUtils.java diff --git a/primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/util/PostgreSQLUtils.java b/src/main/java/com/shortthirdman/primekit/essentials/common/util/PostgreSQLUtils.java similarity index 100% rename from primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/util/PostgreSQLUtils.java rename to src/main/java/com/shortthirdman/primekit/essentials/common/util/PostgreSQLUtils.java diff --git a/primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/util/StringUtils.java b/src/main/java/com/shortthirdman/primekit/essentials/common/util/StringUtils.java similarity index 100% rename from primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/util/StringUtils.java rename to src/main/java/com/shortthirdman/primekit/essentials/common/util/StringUtils.java diff --git a/primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/util/SystemUtils.java b/src/main/java/com/shortthirdman/primekit/essentials/common/util/SystemUtils.java similarity index 100% rename from primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/common/util/SystemUtils.java rename to src/main/java/com/shortthirdman/primekit/essentials/common/util/SystemUtils.java diff --git a/primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/webclient/.gitkeep b/src/main/java/com/shortthirdman/primekit/essentials/core/annotations/.gitkeep similarity index 100% rename from primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/webclient/.gitkeep rename to src/main/java/com/shortthirdman/primekit/essentials/core/annotations/.gitkeep diff --git a/primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/generics/webmvc/AbstractBaseController.java b/src/main/java/com/shortthirdman/primekit/essentials/generics/webmvc/AbstractBaseController.java similarity index 100% rename from primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/generics/webmvc/AbstractBaseController.java rename to src/main/java/com/shortthirdman/primekit/essentials/generics/webmvc/AbstractBaseController.java diff --git a/primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/generics/webmvc/AbstractBaseDTO.java b/src/main/java/com/shortthirdman/primekit/essentials/generics/webmvc/AbstractBaseDTO.java similarity index 100% rename from primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/generics/webmvc/AbstractBaseDTO.java rename to src/main/java/com/shortthirdman/primekit/essentials/generics/webmvc/AbstractBaseDTO.java diff --git a/primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/generics/webmvc/AbstractBaseEntity.java b/src/main/java/com/shortthirdman/primekit/essentials/generics/webmvc/AbstractBaseEntity.java similarity index 100% rename from primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/generics/webmvc/AbstractBaseEntity.java rename to src/main/java/com/shortthirdman/primekit/essentials/generics/webmvc/AbstractBaseEntity.java diff --git a/primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/generics/webmvc/AbstractBaseRepository.java b/src/main/java/com/shortthirdman/primekit/essentials/generics/webmvc/AbstractBaseRepository.java similarity index 100% rename from primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/generics/webmvc/AbstractBaseRepository.java rename to src/main/java/com/shortthirdman/primekit/essentials/generics/webmvc/AbstractBaseRepository.java diff --git a/primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/generics/webmvc/AbstractBaseService.java b/src/main/java/com/shortthirdman/primekit/essentials/generics/webmvc/AbstractBaseService.java similarity index 100% rename from primekit-essentials/src/main/java/com/shortthirdman/primekit/essentials/generics/webmvc/AbstractBaseService.java rename to src/main/java/com/shortthirdman/primekit/essentials/generics/webmvc/AbstractBaseService.java diff --git a/src/main/java/com/shortthirdman/primekit/essentials/webclient/.gitkeep b/src/main/java/com/shortthirdman/primekit/essentials/webclient/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/primekit-essentials/src/test/java/com/shortthirdman/primekit/essentials/ArrayUtilsTest.java b/src/test/java/com/shortthirdman/primekit/essentials/ArrayUtilsTest.java similarity index 100% rename from primekit-essentials/src/test/java/com/shortthirdman/primekit/essentials/ArrayUtilsTest.java rename to src/test/java/com/shortthirdman/primekit/essentials/ArrayUtilsTest.java diff --git a/primekit-essentials/src/test/java/com/shortthirdman/primekit/essentials/CollectionUtilsTests.java b/src/test/java/com/shortthirdman/primekit/essentials/CollectionUtilsTests.java similarity index 100% rename from primekit-essentials/src/test/java/com/shortthirdman/primekit/essentials/CollectionUtilsTests.java rename to src/test/java/com/shortthirdman/primekit/essentials/CollectionUtilsTests.java diff --git a/primekit-essentials/src/test/java/com/shortthirdman/primekit/essentials/DateUtilsTest.java b/src/test/java/com/shortthirdman/primekit/essentials/DateUtilsTest.java similarity index 100% rename from primekit-essentials/src/test/java/com/shortthirdman/primekit/essentials/DateUtilsTest.java rename to src/test/java/com/shortthirdman/primekit/essentials/DateUtilsTest.java diff --git a/primekit-essentials/src/test/java/com/shortthirdman/primekit/essentials/MathUtilsTests.java b/src/test/java/com/shortthirdman/primekit/essentials/MathUtilsTests.java similarity index 100% rename from primekit-essentials/src/test/java/com/shortthirdman/primekit/essentials/MathUtilsTests.java rename to src/test/java/com/shortthirdman/primekit/essentials/MathUtilsTests.java diff --git a/primekit-essentials/src/test/java/com/shortthirdman/primekit/essentials/common/util/LDAPUtilsTest.java b/src/test/java/com/shortthirdman/primekit/essentials/common/util/LDAPUtilsTest.java similarity index 100% rename from primekit-essentials/src/test/java/com/shortthirdman/primekit/essentials/common/util/LDAPUtilsTest.java rename to src/test/java/com/shortthirdman/primekit/essentials/common/util/LDAPUtilsTest.java diff --git a/techstack.md b/techstack.md deleted file mode 100644 index 3664332..0000000 --- a/techstack.md +++ /dev/null @@ -1,159 +0,0 @@ - -
- -# Tech Stack File -![](https://img.stackshare.io/repo.svg "repo") [shortthirdman-org/PrimeKit](https://github.com/shortthirdman-org/PrimeKit)![](https://img.stackshare.io/public_badge.svg "public") -

-|31
Tools used|06/08/24
Report generated| -|------|------| -
- -## Languages (1) - - - - -
- Java -
- Java -
- -
- -## Frameworks (1) - - - - -
- Spring Framework -
- Spring Framework -
- v6.1.6 -
- -## Data (2) - - - - - - -
- PostgreSQL -
- PostgreSQL -
- -
- Spring Data -
- Spring Data -
- -
- -## DevOps (4) - - - - - - - - - - -
- Apache Maven -
- Apache Maven -
- -
- Git -
- Git -
- -
- GitHub Actions -
- GitHub Actions -
- -
- JUnit -
- JUnit -
- -
- - -## Open source packages (23) - -## Apache Maven (23) - -|NAME|VERSION|LAST UPDATED|LAST UPDATED BY|LICENSE|VULNERABILITIES| -|:------|:------|:------|:------|:------|:------| -|[org.springframework.security:spring-security-core](http://spring.io/spring-security)|v6.1.6|06/08/24|Swetank Mohanty |Apache-2.0|[CVE-2024-22234](https://github.com/advisories/GHSA-w3w6-26f2-p474) (High)
[CVE-2024-22257](https://github.com/advisories/GHSA-f3jh-qvm4-mg39) (High)| -|[com.fasterxml.jackson.core:jackson-annotations](http://github.com/FasterXML/jackson)|v2.15.4|06/08/24|Swetank Mohanty |Apache-2.0|N/A| -|[com.fasterxml.jackson.core:jackson-core](https://github.com/FasterXML/jackson-core)|v2.15.4|06/08/24|Swetank Mohanty |Apache-2.0|N/A| -|[commons-codec:commons-codec](https://commons.apache.org/proper/commons-codec/)|v1.15|06/08/24|Swetank Mohanty |Apache-2.0|N/A| -|[commons-io:commons-io](http://commons.apache.org/proper/commons-io/)|v2.11.0|06/08/24|Swetank Mohanty |Apache-2.0|N/A| -|[org.apache.commons:commons-lang3](http://commons.apache.org/proper/commons-lang/)|v3.12.0|06/08/24|Swetank Mohanty |Apache-2.0|N/A| -|[org.hibernate.common:hibernate-commons-annotations](http://hibernate.org)|N/A|06/08/24|Swetank Mohanty |Apache-2.0|N/A| -|[org.hibernate:hibernate-core](http://hibernate.org/orm)|N/A|06/08/24|Swetank Mohanty |LGPL-2.0-only,GPL-3.0-or-later|N/A| -|[org.junit.jupiter:junit-jupiter-api](https://junit.org/junit5/)|v5.10.2|06/08/24|Swetank Mohanty |EPL-2.0|N/A| -|[org.junit.jupiter:junit-jupiter-engine](https://junit.org/junit5/)|v5.10.2|06/08/24|Swetank Mohanty |EPL-2.0|N/A| -|[org.junit.jupiter:junit-jupiter-params](https://junit.org/junit5/)|v5.10.2|06/08/24|Swetank Mohanty |EPL-2.0|N/A| -|[org.junit.platform:junit-platform-runner](https://junit.org/junit5/)|v1.10.2|06/08/24|Swetank Mohanty |EPL-2.0|N/A| -|[org.postgresql:postgresql](http://jdbc.postgresql.org)|v42.7.3|06/08/24|Swetank Mohanty |BSD-2-Clause|N/A| -|[org.projectlombok:lombok](https://projectlombok.org)|v1.18.30|06/08/24|Swetank Mohanty |MIT|N/A| -|[org.springframework.data:spring-data-commons](https://www.spring.io/spring-data)|v3.2.5|06/08/24|Swetank Mohanty |Apache-2.0|N/A| -|[org.springframework.data:spring-data-jpa](https://projects.spring.io/spring-data-jpa)|v3.2.5|06/08/24|Swetank Mohanty |Apache-2.0|N/A| -|[org.springframework:spring-aop](https://github.com/spring-projects/spring-framework)|v6.1.6|06/08/24|Swetank Mohanty |Apache-2.0|N/A| -|[org.springframework:spring-beans](https://github.com/spring-projects/spring-framework)|v6.1.6|06/08/24|Swetank Mohanty |Apache-2.0|N/A| -|[org.springframework:spring-context](https://github.com/spring-projects/spring-framework)|v6.1.6|06/08/24|Swetank Mohanty |Apache-2.0|N/A| -|[org.springframework:spring-context-support](https://github.com/spring-projects/spring-framework)|v6.1.6|06/08/24|Swetank Mohanty |Apache-2.0|N/A| -|[org.springframework:spring-core](https://github.com/spring-projects/spring-framework)|v6.1.6|06/08/24|Swetank Mohanty |Apache-2.0|N/A| -|[org.springframework:spring-web](https://github.com/spring-projects/spring-framework)|v6.1.6|06/08/24|Swetank Mohanty |Apache-2.0|N/A| -|[org.springframework:spring-webmvc](https://github.com/spring-projects/spring-framework)|v6.1.6|06/08/24|Swetank Mohanty |Apache-2.0|N/A| - -
-
- -Generated via [Stack File](https://github.com/marketplace/stack-file) diff --git a/techstack.yml b/techstack.yml deleted file mode 100644 index 38a7c39..0000000 --- a/techstack.yml +++ /dev/null @@ -1,421 +0,0 @@ -repo_name: shortthirdman-org/PrimeKit -report_id: 1c35374bcba36735c57e49bcdc75aac6 -version: 0.1 -repo_type: Public -timestamp: '2024-06-08T18:21:41+00:00' -requested_by: shortthirdman -provider: github -branch: main -detected_tools_count: 31 -tools: -- name: Java - description: A concurrent, class-based, object-oriented, language specifically designed - to have as few implementation dependencies as possible - website_url: https://www.java.com - open_source: true - hosted_saas: false - category: Languages & Frameworks - sub_category: Languages - image_url: https://img.stackshare.io/service/995/K85ZWV2F.png - detection_source_url: https://github.com/shortthirdman-org/PrimeKit - detection_source: Repo Metadata -- name: Spring Framework - description: An application framework and inversion of control container for the - Java platform - website_url: https://spring.io/projects/spring-framework - version: 6.1.6 - license: Apache-2.0 - open_source: true - hosted_saas: false - category: Languages & Frameworks - sub_category: Frameworks (Full Stack) - image_url: https://img.stackshare.io/service/2006/spring-framework-project-logo.png - detection_source_url: https://github.com/shortthirdman-org/PrimeKit/blob/main/primekit-essentials/pom.xml - detection_source: primekit-essentials/pom.xml - last_updated_by: Swetank Mohanty - last_updated_on: 2024-06-08 18:03:01.000000000 Z -- name: PostgreSQL - description: A powerful, open source object-relational database system - website_url: http://www.postgresql.org/ - open_source: true - hosted_saas: false - category: Data Stores - sub_category: Databases - image_url: https://img.stackshare.io/service/1028/ASOhU5xJ.png - detection_source_url: https://github.com/shortthirdman-org/PrimeKit/blob/main/primekit-essentials/pom.xml - detection_source: primekit-essentials/pom.xml - last_updated_by: Swetank Mohanty - last_updated_on: 2024-06-08 18:03:01.000000000 Z -- name: Spring Data - description: Provides a consistent approach to data access – relational, non-relational, - map-reduce, and beyond - website_url: https://spring.io/projects/spring-data - license: Apache-2.0 - open_source: true - hosted_saas: false - category: Data Stores - sub_category: Database Tools - image_url: https://img.stackshare.io/service/7624/IG6D4Ro2_400x400.png - detection_source_url: https://github.com/shortthirdman-org/PrimeKit/blob/main/primekit-essentials/pom.xml - detection_source: primekit-essentials/pom.xml - last_updated_by: Swetank Mohanty - last_updated_on: 2024-06-08 18:03:01.000000000 Z -- name: Apache Maven - description: Apache build manager for Java projects. - website_url: http://maven.apache.org/ - license: Apache-2.0 - open_source: true - hosted_saas: false - category: Build, Test, Deploy - sub_category: Java Build Tools - image_url: https://img.stackshare.io/package_manager/977/default_9833f2ef0bbc2a946b4cc5e9307264033361076b.png - detection_source_url: https://github.com/shortthirdman-org/PrimeKit/blob/main/primekit-essentials/.mvn/maven.config - detection_source: primekit-essentials/.mvn/maven.config - last_updated_by: Swetank Mohanty - last_updated_on: 2024-06-08 18:03:01.000000000 Z -- name: Git - description: Fast, scalable, distributed revision control system - website_url: http://git-scm.com/ - open_source: true - hosted_saas: false - category: Build, Test, Deploy - sub_category: Version Control System - image_url: https://img.stackshare.io/service/1046/git.png - detection_source_url: https://github.com/shortthirdman-org/PrimeKit - detection_source: Repo Metadata -- name: GitHub Actions - description: Automate your workflow from idea to production - website_url: https://github.com/features/actions - open_source: false - hosted_saas: true - category: Build, Test, Deploy - sub_category: Continuous Integration - image_url: https://img.stackshare.io/service/11563/actions.png - detection_source_url: https://github.com/shortthirdman-org/PrimeKit/blob/main/.github/workflows/codeql.yml - detection_source: ".github/workflows/codeql.yml" - last_updated_by: Swetank Mohanty - last_updated_on: 2024-06-08 18:03:01.000000000 Z -- name: JUnit - description: A programmer-oriented testing framework for Java - website_url: http://junit.org/ - license: EPL-1.0 - open_source: true - hosted_saas: false - category: Build, Test, Deploy - sub_category: Testing Frameworks - image_url: https://img.stackshare.io/service/2020/874086.png - detection_source_url: https://github.com/shortthirdman-org/PrimeKit/blob/main/primekit-essentials/pom.xml - detection_source: primekit-essentials/pom.xml - last_updated_by: Swetank Mohanty - last_updated_on: 2024-06-08 18:03:01.000000000 Z -- name: org.springframework.security:spring-security-core - description: Spring-security-core - version: 6.1.6 - license: Apache-2.0 - open_source: true - hosted_saas: false - category: Libraries - sub_category: Maven Packages - image_url: https://img.stackshare.io/package/maven/image.png - detection_source_url: https://github.com/shortthirdman-org/PrimeKit/blob/main/primekit-essentials/pom.xml - detection_source: primekit-essentials/pom.xml - last_updated_by: Swetank Mohanty - last_updated_on: 2024-06-08 18:03:01.000000000 Z - vulnerabilities: - - name: Broken Access Control in Spring Security With Direct Use of isFullyAuthenticated - cve_id: CVE-2024-22234 - cve_url: https://github.com/advisories/GHSA-w3w6-26f2-p474 - detected_date: Feb 21 - severity: high - first_patched: 6.1.7 - - name: Erroneous authentication pass in Spring Security - cve_id: CVE-2024-22257 - cve_url: https://github.com/advisories/GHSA-f3jh-qvm4-mg39 - detected_date: Mar 19 - severity: high - first_patched: 6.1.8 -- name: com.fasterxml.jackson.core:jackson-annotations - description: Core annotations used for value types - version: 2.15.4 - license: Apache-2.0 - open_source: true - hosted_saas: false - category: Libraries - sub_category: Maven Packages - image_url: https://img.stackshare.io/package/maven/image.png - detection_source_url: https://github.com/shortthirdman-org/PrimeKit/blob/main/primekit-essentials/pom.xml - detection_source: primekit-essentials/pom.xml - last_updated_by: Swetank Mohanty - last_updated_on: 2024-06-08 18:03:01.000000000 Z -- name: com.fasterxml.jackson.core:jackson-core - description: Core Jackson processing abstractions - version: 2.15.4 - license: Apache-2.0 - open_source: true - hosted_saas: false - category: Libraries - sub_category: Maven Packages - image_url: https://img.stackshare.io/package/maven/image.png - detection_source_url: https://github.com/shortthirdman-org/PrimeKit/blob/main/primekit-essentials/pom.xml - detection_source: primekit-essentials/pom.xml - last_updated_by: Swetank Mohanty - last_updated_on: 2024-06-08 18:03:01.000000000 Z -- name: commons-codec:commons-codec - description: The Apache Commons Codec package contains simple encoder and decoders - for various formats such as Base64 and Hexadecimal - version: '1.15' - license: Apache-2.0 - open_source: true - hosted_saas: false - category: Libraries - sub_category: Maven Packages - image_url: https://img.stackshare.io/package/maven/image.png - detection_source_url: https://github.com/shortthirdman-org/PrimeKit/blob/main/primekit-essentials/pom.xml - detection_source: primekit-essentials/pom.xml - last_updated_by: Swetank Mohanty - last_updated_on: 2024-06-08 18:03:01.000000000 Z -- name: commons-io:commons-io - description: The Apache Commons IO library contains utility classes - version: 2.11.0 - license: Apache-2.0 - open_source: true - hosted_saas: false - category: Libraries - sub_category: Maven Packages - image_url: https://img.stackshare.io/package/maven/image.png - detection_source_url: https://github.com/shortthirdman-org/PrimeKit/blob/main/primekit-essentials/pom.xml - detection_source: primekit-essentials/pom.xml - last_updated_by: Swetank Mohanty - last_updated_on: 2024-06-08 18:03:01.000000000 Z -- name: org.apache.commons:commons-lang3 - description: Apache Commons Lang - version: 3.12.0 - license: Apache-2.0 - open_source: true - hosted_saas: false - category: Libraries - sub_category: Maven Packages - image_url: https://img.stackshare.io/package/maven/image.png - detection_source_url: https://github.com/shortthirdman-org/PrimeKit/blob/main/primekit-essentials/pom.xml - detection_source: primekit-essentials/pom.xml - last_updated_by: Swetank Mohanty - last_updated_on: 2024-06-08 18:03:01.000000000 Z -- name: org.hibernate.common:hibernate-commons-annotations - description: Common reflection code used in support of annotation processing - license: Apache-2.0 - open_source: true - hosted_saas: false - category: Libraries - sub_category: Maven Packages - image_url: https://img.stackshare.io/package/maven/image.png - detection_source_url: https://github.com/shortthirdman-org/PrimeKit/blob/main/primekit-essentials/pom.xml - detection_source: primekit-essentials/pom.xml - last_updated_by: Swetank Mohanty - last_updated_on: 2024-06-08 18:03:01.000000000 Z -- name: org.hibernate:hibernate-core - description: Hibernate's core ORM functionality - license: LGPL-2.0-only,GPL-3.0-or-later - open_source: true - hosted_saas: false - category: Libraries - sub_category: Maven Packages - image_url: https://img.stackshare.io/package/maven/image.png - detection_source_url: https://github.com/shortthirdman-org/PrimeKit/blob/main/primekit-essentials/pom.xml - detection_source: primekit-essentials/pom.xml - last_updated_by: Swetank Mohanty - last_updated_on: 2024-06-08 18:03:01.000000000 Z -- name: org.junit.jupiter:junit-jupiter-api - description: Module "junit-jupiter-api" of JUnit 5 - version: 5.10.2 - license: EPL-2.0 - open_source: true - hosted_saas: false - category: Libraries - sub_category: Maven Packages - image_url: https://img.stackshare.io/package/maven/image.png - detection_source_url: https://github.com/shortthirdman-org/PrimeKit/blob/main/primekit-essentials/pom.xml - detection_source: primekit-essentials/pom.xml - last_updated_by: Swetank Mohanty - last_updated_on: 2024-06-08 18:03:01.000000000 Z -- name: org.junit.jupiter:junit-jupiter-engine - description: Module "junit-jupiter-engine" of JUnit 5 - version: 5.10.2 - license: EPL-2.0 - open_source: true - hosted_saas: false - category: Libraries - sub_category: Maven Packages - image_url: https://img.stackshare.io/package/maven/image.png - detection_source_url: https://github.com/shortthirdman-org/PrimeKit/blob/main/primekit-essentials/pom.xml - detection_source: primekit-essentials/pom.xml - last_updated_by: Swetank Mohanty - last_updated_on: 2024-06-08 18:03:01.000000000 Z -- name: org.junit.jupiter:junit-jupiter-params - description: Module "junit-jupiter-params" of JUnit 5 - version: 5.10.2 - license: EPL-2.0 - open_source: true - hosted_saas: false - category: Libraries - sub_category: Maven Packages - image_url: https://img.stackshare.io/package/maven/image.png - detection_source_url: https://github.com/shortthirdman-org/PrimeKit/blob/main/primekit-essentials/pom.xml - detection_source: primekit-essentials/pom.xml - last_updated_by: Swetank Mohanty - last_updated_on: 2024-06-08 18:03:01.000000000 Z -- name: org.junit.platform:junit-platform-runner - description: Module "junit-platform-runner" of JUnit 5 - version: 1.10.2 - license: EPL-2.0 - open_source: true - hosted_saas: false - category: Libraries - sub_category: Maven Packages - image_url: https://img.stackshare.io/package/maven/image.png - detection_source_url: https://github.com/shortthirdman-org/PrimeKit/blob/main/primekit-essentials/pom.xml - detection_source: primekit-essentials/pom.xml - last_updated_by: Swetank Mohanty - last_updated_on: 2024-06-08 18:03:01.000000000 Z -- name: org.postgresql:postgresql - description: The PostgreSQL Driver JDBC4 - version: 42.7.3 - license: BSD-2-Clause - open_source: true - hosted_saas: false - category: Libraries - sub_category: Maven Packages - image_url: https://img.stackshare.io/package/maven/image.png - detection_source_url: https://github.com/shortthirdman-org/PrimeKit/blob/main/primekit-essentials/pom.xml - detection_source: primekit-essentials/pom.xml - last_updated_by: Swetank Mohanty - last_updated_on: 2024-06-08 18:03:01.000000000 Z -- name: org.projectlombok:lombok - description: 'Spice up your java: Automatic Resource Management' - version: 1.18.30 - license: MIT - open_source: true - hosted_saas: false - category: Libraries - sub_category: Maven Packages - image_url: https://img.stackshare.io/package/maven/image.png - detection_source_url: https://github.com/shortthirdman-org/PrimeKit/blob/main/primekit-essentials/pom.xml - detection_source: primekit-essentials/pom.xml - last_updated_by: Swetank Mohanty - last_updated_on: 2024-06-08 18:03:01.000000000 Z -- name: org.springframework.data:spring-data-commons - description: Global parent pom.xml to be used by Spring Data modules - version: 3.2.5 - license: Apache-2.0 - open_source: true - hosted_saas: false - category: Libraries - sub_category: Maven Packages - image_url: https://img.stackshare.io/package/maven/image.png - detection_source_url: https://github.com/shortthirdman-org/PrimeKit/blob/main/primekit-essentials/pom.xml - detection_source: primekit-essentials/pom.xml - last_updated_by: Swetank Mohanty - last_updated_on: 2024-06-08 18:03:01.000000000 Z -- name: org.springframework.data:spring-data-jpa - description: Spring Data module for JPA repositories - version: 3.2.5 - license: Apache-2.0 - open_source: true - hosted_saas: false - category: Libraries - sub_category: Maven Packages - image_url: https://img.stackshare.io/package/maven/image.png - detection_source_url: https://github.com/shortthirdman-org/PrimeKit/blob/main/primekit-essentials/pom.xml - detection_source: primekit-essentials/pom.xml - last_updated_by: Swetank Mohanty - last_updated_on: 2024-06-08 18:03:01.000000000 Z -- name: org.springframework:spring-aop - description: Spring AOP - version: 6.1.6 - license: Apache-2.0 - open_source: true - hosted_saas: false - category: Libraries - sub_category: Maven Packages - image_url: https://img.stackshare.io/package/maven/image.png - detection_source_url: https://github.com/shortthirdman-org/PrimeKit/blob/main/primekit-essentials/pom.xml - detection_source: primekit-essentials/pom.xml - last_updated_by: Swetank Mohanty - last_updated_on: 2024-06-08 18:03:01.000000000 Z -- name: org.springframework:spring-beans - description: Spring Beans - version: 6.1.6 - license: Apache-2.0 - open_source: true - hosted_saas: false - category: Libraries - sub_category: Maven Packages - image_url: https://img.stackshare.io/package/maven/image.png - detection_source_url: https://github.com/shortthirdman-org/PrimeKit/blob/main/primekit-essentials/pom.xml - detection_source: primekit-essentials/pom.xml - last_updated_by: Swetank Mohanty - last_updated_on: 2024-06-08 18:03:01.000000000 Z -- name: org.springframework:spring-context - description: Spring Context - version: 6.1.6 - license: Apache-2.0 - open_source: true - hosted_saas: false - category: Libraries - sub_category: Maven Packages - image_url: https://img.stackshare.io/package/maven/image.png - detection_source_url: https://github.com/shortthirdman-org/PrimeKit/blob/main/primekit-essentials/pom.xml - detection_source: primekit-essentials/pom.xml - last_updated_by: Swetank Mohanty - last_updated_on: 2024-06-08 18:03:01.000000000 Z -- name: org.springframework:spring-context-support - description: Spring Context Support - version: 6.1.6 - license: Apache-2.0 - open_source: true - hosted_saas: false - category: Libraries - sub_category: Maven Packages - image_url: https://img.stackshare.io/package/maven/image.png - detection_source_url: https://github.com/shortthirdman-org/PrimeKit/blob/main/primekit-essentials/pom.xml - detection_source: primekit-essentials/pom.xml - last_updated_by: Swetank Mohanty - last_updated_on: 2024-06-08 18:03:01.000000000 Z -- name: org.springframework:spring-core - description: Spring Core - version: 6.1.6 - license: Apache-2.0 - open_source: true - hosted_saas: false - category: Libraries - sub_category: Maven Packages - image_url: https://img.stackshare.io/package/maven/image.png - detection_source_url: https://github.com/shortthirdman-org/PrimeKit/blob/main/primekit-essentials/pom.xml - detection_source: primekit-essentials/pom.xml - last_updated_by: Swetank Mohanty - last_updated_on: 2024-06-08 18:03:01.000000000 Z -- name: org.springframework:spring-web - description: Spring Web - version: 6.1.6 - license: Apache-2.0 - open_source: true - hosted_saas: false - category: Libraries - sub_category: Maven Packages - image_url: https://img.stackshare.io/package/maven/image.png - detection_source_url: https://github.com/shortthirdman-org/PrimeKit/blob/main/primekit-essentials/pom.xml - detection_source: primekit-essentials/pom.xml - last_updated_by: Swetank Mohanty - last_updated_on: 2024-06-08 18:03:01.000000000 Z -- name: org.springframework:spring-webmvc - description: Spring Web MVC - version: 6.1.6 - license: Apache-2.0 - open_source: true - hosted_saas: false - category: Libraries - sub_category: Maven Packages - image_url: https://img.stackshare.io/package/maven/image.png - detection_source_url: https://github.com/shortthirdman-org/PrimeKit/blob/main/primekit-essentials/pom.xml - detection_source: primekit-essentials/pom.xml - last_updated_by: Swetank Mohanty - last_updated_on: 2024-06-08 18:03:01.000000000 Z From 86a2262623bf5b3bdf508317b65f5163ead51ac7 Mon Sep 17 00:00:00 2001 From: Swetank Mohanty Date: Wed, 2 Apr 2025 00:06:02 +0530 Subject: [PATCH 02/12] core: Added missing files from previous unmerged branch --- pom.xml | 15 ++++ .../essentials/common/util/JwtUtils.java | 78 +++++++++++++++++++ .../common/util/LinkedListUtils.java | 6 ++ .../essentials/common/util/PaymentUtils.java | 46 +++++++++++ .../common/util/PaymentUtilsTest.java | 25 ++++++ 5 files changed, 170 insertions(+) create mode 100644 src/main/java/com/shortthirdman/primekit/essentials/common/util/JwtUtils.java create mode 100644 src/main/java/com/shortthirdman/primekit/essentials/common/util/LinkedListUtils.java create mode 100644 src/main/java/com/shortthirdman/primekit/essentials/common/util/PaymentUtils.java create mode 100644 src/test/java/com/shortthirdman/primekit/essentials/common/util/PaymentUtilsTest.java diff --git a/pom.xml b/pom.xml index d6a98b0..36d9ef4 100644 --- a/pom.xml +++ b/pom.xml @@ -17,6 +17,7 @@ 1.8 21 1.18.32 + 0.12.6 6.2.5 2.15.4 4.0.2 @@ -167,6 +168,19 @@ jakarta.persistence-api 3.2.0-M2 + + + io.jsonwebtoken + jjwt-api + ${jjwt.version} + + + io.jsonwebtoken + jjwt-impl + ${jjwt.version} + runtime + + com.fasterxml.jackson.core jackson-core @@ -177,6 +191,7 @@ jackson-annotations ${fasterxml-jackson.version} + org.apache.commons commons-lang3 diff --git a/src/main/java/com/shortthirdman/primekit/essentials/common/util/JwtUtils.java b/src/main/java/com/shortthirdman/primekit/essentials/common/util/JwtUtils.java new file mode 100644 index 0000000..076435e --- /dev/null +++ b/src/main/java/com/shortthirdman/primekit/essentials/common/util/JwtUtils.java @@ -0,0 +1,78 @@ +// Copyright (c) ShortThirdMan 2025. +package com.shortthirdman.primekit.essentials.common.util; + +import io.jsonwebtoken.*; +import io.jsonwebtoken.io.Decoders; +import io.jsonwebtoken.security.Keys; +import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException; +import org.springframework.security.core.userdetails.UserDetails; + +import javax.crypto.SecretKey; +import java.nio.charset.StandardCharsets; +import java.util.Date; +import java.util.Map; + +public final class JwtUtils { + + private JwtUtils() {} + + /** + * @return the decoded JWT secret in + */ + public static SecretKey getSecretKey() { + var jwtSecret = System.getProperty("jwt.secret"); + byte[] keyBytes = Decoders.BASE64.decode(jwtSecret); + return Keys.hmacShaKeyFor(keyBytes); + } + + public static String generateToken(UserDetails userDetails, Map extraClaims) { + var jwtSecret = System.getProperty("jwt.secret"); + byte[] keyBytes = jwtSecret.getBytes(StandardCharsets.UTF_8); + SecretKey secretKey = Keys.hmacShaKeyFor(keyBytes); + + return Jwts.builder() + .claims() + .add(extraClaims) + .subject(userDetails.getUsername()) + .issuedAt(new Date(System.currentTimeMillis())) + .expiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60)) + .and() + .signWith(secretKey, Jwts.SIG.HS512) + .compact(); + } + + /** + * @param token the token to validate + * @return true if valid, else false + */ + public static boolean validateTokenExpiration(String token) { + var jwtSecret = System.getProperty("jwt.secret"); + byte[] keyBytes = Decoders.BASE64.decode(jwtSecret); + Claims claims = Jwts.parser().verifyWith(getSecretKey()) + .build() + .parseSignedClaims(token) + .getPayload(); + return claims.getExpiration().after(new Date()); + } + + /** + * @param token the token to validate + * @return true if valid, else false + */ + public static boolean validateToken(String token) { + try { + Jwts.parser().verifyWith(getSecretKey()) + .build() + .parseSignedClaims(token); + return true; + } catch(SecurityException | MalformedJwtException e) { + throw new AuthenticationCredentialsNotFoundException("JWT was expired or incorrect"); + } catch (ExpiredJwtException e) { + throw new AuthenticationCredentialsNotFoundException("Expired JWT token."); + } catch (UnsupportedJwtException e) { + throw new AuthenticationCredentialsNotFoundException("Unsupported JWT token."); + } catch (IllegalArgumentException e) { + throw new AuthenticationCredentialsNotFoundException("JWT token compact of handler are invalid."); + } + } +} diff --git a/src/main/java/com/shortthirdman/primekit/essentials/common/util/LinkedListUtils.java b/src/main/java/com/shortthirdman/primekit/essentials/common/util/LinkedListUtils.java new file mode 100644 index 0000000..5184357 --- /dev/null +++ b/src/main/java/com/shortthirdman/primekit/essentials/common/util/LinkedListUtils.java @@ -0,0 +1,6 @@ +package com.shortthirdman.primekit.essentials.common.util; + +public class LinkedListUtils { + + private LinkedListUtils() {} +} diff --git a/src/main/java/com/shortthirdman/primekit/essentials/common/util/PaymentUtils.java b/src/main/java/com/shortthirdman/primekit/essentials/common/util/PaymentUtils.java new file mode 100644 index 0000000..6ddff46 --- /dev/null +++ b/src/main/java/com/shortthirdman/primekit/essentials/common/util/PaymentUtils.java @@ -0,0 +1,46 @@ +// Copyright (c) ShortThirdMan 2025. +package com.shortthirdman.primekit.essentials.common.util; + +/** + * Utility methods for payments + */ +public final class PaymentUtils { + + private PaymentUtils() {} + + /** + * Validates a credit card number using Luhn's algorithm. + * + * @param cardNumber The credit/debit card number as a string. + * @return true if the number is valid, false otherwise. + */ + public static boolean isValidCardNumber(String cardNumber) { + // Remove any non-digit characters + String sanitizedNumber = cardNumber.replaceAll("\\D", ""); + + int length = sanitizedNumber.length(); + if (length == 0) { + return false; + } + + int sum = 0; + boolean shouldDouble = false; + + // Iterate over the digits of the number, starting from the end + for (int i = length - 1; i >= 0; i--) { + int digit = Character.getNumericValue(sanitizedNumber.charAt(i)); + + if (shouldDouble) { + digit *= 2; + if (digit > 9) { + digit -= 9; + } + } + + sum += digit; + shouldDouble = !shouldDouble; + } + + return (sum % 10 == 0); + } +} diff --git a/src/test/java/com/shortthirdman/primekit/essentials/common/util/PaymentUtilsTest.java b/src/test/java/com/shortthirdman/primekit/essentials/common/util/PaymentUtilsTest.java new file mode 100644 index 0000000..267669d --- /dev/null +++ b/src/test/java/com/shortthirdman/primekit/essentials/common/util/PaymentUtilsTest.java @@ -0,0 +1,25 @@ +// Copyright (c) ShortThirdMan 2025. +package com.shortthirdman.primekit.essentials.common.util; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class PaymentUtilsTest { + + @Test + void test_validCardNumbers() { + assertTrue(PaymentUtils.isValidCardNumber("4532015112830366"), "Valid credit card number"); + assertTrue(PaymentUtils.isValidCardNumber("6011514435546211"), "Valid credit card number"); + assertTrue(PaymentUtils.isValidCardNumber("378282246310005"), "Valid American Express number."); + } + + @Test + void test_invalidCardNumbers() { + assertFalse(PaymentUtils.isValidCardNumber("123456789012345"), "Invalid card number"); + assertFalse(PaymentUtils.isValidCardNumber("0000000000000000"), "Invalid card number"); + assertFalse(PaymentUtils.isValidCardNumber("4532015112830367"), "Slightly altered from a valid number to become invalid."); + assertFalse(PaymentUtils.isValidCardNumber("6011514435546210"), "Slightly altered from a valid number to become invalid."); + } +} \ No newline at end of file From d10e97517c8e2de51d1e05f57eaeea36eae5d09a Mon Sep 17 00:00:00 2001 From: Swetank Mohanty Date: Wed, 2 Apr 2025 00:35:00 +0530 Subject: [PATCH 03/12] core: Added missing dependencies --- pom.xml | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/pom.xml b/pom.xml index 36d9ef4..d0c463c 100644 --- a/pom.xml +++ b/pom.xml @@ -19,10 +19,14 @@ 1.18.32 0.12.6 6.2.5 + 3.2.5 2.15.4 4.0.2 + 5.6.10.Final 5.11.0 + 42.7.3 + 5.10.2 3.19.0 @@ -143,6 +147,25 @@ spring-jpa 2.0.8 + + + org.springframework.data + spring-data-jpa + ${spring-data.version} + + + org.springframework.data + spring-data-commons + ${spring-data.version} + + + + org.postgresql + postgresql + ${postgresql.version} + provided + + commons-codec commons-codec @@ -203,6 +226,7 @@ ${lombok.version} true + org.assertj assertj-core @@ -220,6 +244,24 @@ junit-jupiter-params test + + org.junit.jupiter + junit-jupiter-engine + ${junit-jupiter.version} + test + + + org.junit.platform + junit-platform-runner + 1.10.2 + test + + + org.junit.platform + junit-platform-suite-engine + 1.9.1 + test + From 92fe11b9bb8dd3c52a0752d8d86e56d5756890d7 Mon Sep 17 00:00:00 2001 From: Swetank Mohanty Date: Wed, 2 Apr 2025 00:35:20 +0530 Subject: [PATCH 04/12] core: Removed JVM and Maven configuration files --- .mvn/jvm.config | 0 .mvn/maven.config | 1 - 2 files changed, 1 deletion(-) delete mode 100644 .mvn/jvm.config delete mode 100644 .mvn/maven.config diff --git a/.mvn/jvm.config b/.mvn/jvm.config deleted file mode 100644 index e69de29..0000000 diff --git a/.mvn/maven.config b/.mvn/maven.config deleted file mode 100644 index 31c8930..0000000 --- a/.mvn/maven.config +++ /dev/null @@ -1 +0,0 @@ ---no-transfer-progress \ No newline at end of file From e8d1179bf3a1e8aab196c212b3b3ac381079d259 Mon Sep 17 00:00:00 2001 From: Swetank Mohanty Date: Fri, 9 May 2025 17:35:09 +0530 Subject: [PATCH 05/12] core: Added WebUtils for utility methods related to web --- .../essentials/common/util/WebUtils.java | 35 +++++++++++++++++++ .../essentials/common/util/WebUtilsTest.java | 14 ++++++++ 2 files changed, 49 insertions(+) create mode 100644 src/main/java/com/shortthirdman/primekit/essentials/common/util/WebUtils.java create mode 100644 src/test/java/com/shortthirdman/primekit/essentials/common/util/WebUtilsTest.java diff --git a/src/main/java/com/shortthirdman/primekit/essentials/common/util/WebUtils.java b/src/main/java/com/shortthirdman/primekit/essentials/common/util/WebUtils.java new file mode 100644 index 0000000..14fe018 --- /dev/null +++ b/src/main/java/com/shortthirdman/primekit/essentials/common/util/WebUtils.java @@ -0,0 +1,35 @@ +package com.shortthirdman.primekit.essentials.common.util; + +import java.util.Optional; + +/** + * Utility class for web-related operations. + * @author ShortThirdMan + * @version 1.0 + */ +public final class WebUtils { + + private WebUtils() {} + + /** + * Validates a URL string using regex. + * @param url the URL string to validate + * @return true if the URL is valid, false otherwise + */ + public static boolean isValidURL(String url) { + return Optional.ofNullable(url) + .map(u -> u.matches("^(http|https)://[\\w.-]+(?:\\.[\\w.-]+)+.*$")) + .orElse(false); + } + + /** + * Checks whether the input is a valid email address. + * @param email the email address to check + * @return true if the email address is valid, false otherwise + */ + public static boolean isValidEmail(String email) { + return Optional.ofNullable(email) + .map(e -> e.matches("^[\\w._%+-]+@[\\w.-]+\\.[a-zA-Z]{2,}$")) + .orElse(false); + } +} diff --git a/src/test/java/com/shortthirdman/primekit/essentials/common/util/WebUtilsTest.java b/src/test/java/com/shortthirdman/primekit/essentials/common/util/WebUtilsTest.java new file mode 100644 index 0000000..73b454b --- /dev/null +++ b/src/test/java/com/shortthirdman/primekit/essentials/common/util/WebUtilsTest.java @@ -0,0 +1,14 @@ +package com.shortthirdman.primekit.essentials.common.util; + +import org.junit.jupiter.api.Test; + +class WebUtilsTest { + + @Test + void testValidURL() { + } + + @Test + void testValidEmail() { + } +} \ No newline at end of file From 41035e04d969edfe50546a18bc422d33a225469e Mon Sep 17 00:00:00 2001 From: Swetank Mohanty Date: Fri, 9 May 2025 17:36:49 +0530 Subject: [PATCH 06/12] core(strategy): Added PaymentContext and PaymentStrategy using strategy pattern --- .../core/strategy/PaymentContext.java | 29 +++++++++++++++++++ .../core/strategy/PaymentStrategy.java | 8 +++++ 2 files changed, 37 insertions(+) create mode 100644 src/main/java/com/shortthirdman/primekit/essentials/core/strategy/PaymentContext.java create mode 100644 src/main/java/com/shortthirdman/primekit/essentials/core/strategy/PaymentStrategy.java diff --git a/src/main/java/com/shortthirdman/primekit/essentials/core/strategy/PaymentContext.java b/src/main/java/com/shortthirdman/primekit/essentials/core/strategy/PaymentContext.java new file mode 100644 index 0000000..3e80c28 --- /dev/null +++ b/src/main/java/com/shortthirdman/primekit/essentials/core/strategy/PaymentContext.java @@ -0,0 +1,29 @@ +package com.shortthirdman.primekit.essentials.core.strategy; + +import org.springframework.stereotype.Component; + +@Component +public class PaymentContext { + + private final PaymentStrategy strategy; + + public PaymentContext(PaymentStrategy strategy) { + this.strategy = strategy; + } + + public void checkout(double amount) { + if (strategy == null) { + throw new IllegalStateException("Payment strategy not set."); + } + + strategy.pay(amount); + } + + public void checkout(Double amount) { + if (strategy == null) { + throw new IllegalStateException("Payment strategy not set."); + } + + strategy.pay(amount); + } +} diff --git a/src/main/java/com/shortthirdman/primekit/essentials/core/strategy/PaymentStrategy.java b/src/main/java/com/shortthirdman/primekit/essentials/core/strategy/PaymentStrategy.java new file mode 100644 index 0000000..fd6336a --- /dev/null +++ b/src/main/java/com/shortthirdman/primekit/essentials/core/strategy/PaymentStrategy.java @@ -0,0 +1,8 @@ +package com.shortthirdman.primekit.essentials.core.strategy; + +public interface PaymentStrategy { + + void pay(double amount); + + void pay(Double amount); +} From 8b62c80e34cf52b6acc3ad115247c5b7cc162800 Mon Sep 17 00:00:00 2001 From: Swetank Mohanty Date: Fri, 9 May 2025 17:38:07 +0530 Subject: [PATCH 07/12] core(utils): Moved package according to source packaging --- .../primekit/essentials/ArrayUtilsTest.java | 4 ---- .../common/util/ArrayUtilsTest.java | 4 ++++ .../util/CollectionUtilsTest.java} | 9 ++++---- .../{ => common/util}/DateUtilsTest.java | 22 +++++++++---------- .../util/MathUtilsTest.java} | 12 +++++----- 5 files changed, 25 insertions(+), 26 deletions(-) delete mode 100644 src/test/java/com/shortthirdman/primekit/essentials/ArrayUtilsTest.java create mode 100644 src/test/java/com/shortthirdman/primekit/essentials/common/util/ArrayUtilsTest.java rename src/test/java/com/shortthirdman/primekit/essentials/{CollectionUtilsTests.java => common/util/CollectionUtilsTest.java} (88%) rename src/test/java/com/shortthirdman/primekit/essentials/{ => common/util}/DateUtilsTest.java (92%) rename src/test/java/com/shortthirdman/primekit/essentials/{MathUtilsTests.java => common/util/MathUtilsTest.java} (81%) diff --git a/src/test/java/com/shortthirdman/primekit/essentials/ArrayUtilsTest.java b/src/test/java/com/shortthirdman/primekit/essentials/ArrayUtilsTest.java deleted file mode 100644 index 9b6da88..0000000 --- a/src/test/java/com/shortthirdman/primekit/essentials/ArrayUtilsTest.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.shortthirdman.primekit.essentials; - -public class ArrayUtilsTest { -} diff --git a/src/test/java/com/shortthirdman/primekit/essentials/common/util/ArrayUtilsTest.java b/src/test/java/com/shortthirdman/primekit/essentials/common/util/ArrayUtilsTest.java new file mode 100644 index 0000000..70b9413 --- /dev/null +++ b/src/test/java/com/shortthirdman/primekit/essentials/common/util/ArrayUtilsTest.java @@ -0,0 +1,4 @@ +package com.shortthirdman.primekit.essentials.common.util; + +class ArrayUtilsTest { +} diff --git a/src/test/java/com/shortthirdman/primekit/essentials/CollectionUtilsTests.java b/src/test/java/com/shortthirdman/primekit/essentials/common/util/CollectionUtilsTest.java similarity index 88% rename from src/test/java/com/shortthirdman/primekit/essentials/CollectionUtilsTests.java rename to src/test/java/com/shortthirdman/primekit/essentials/common/util/CollectionUtilsTest.java index 8f706eb..068ee99 100644 --- a/src/test/java/com/shortthirdman/primekit/essentials/CollectionUtilsTests.java +++ b/src/test/java/com/shortthirdman/primekit/essentials/common/util/CollectionUtilsTest.java @@ -1,6 +1,5 @@ -package com.shortthirdman.primekit.essentials; +package com.shortthirdman.primekit.essentials.common.util; -import com.shortthirdman.primekit.essentials.common.util.CollectionUtils; import org.junit.jupiter.api.Test; import java.util.HashMap; @@ -13,10 +12,10 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; -public class CollectionUtilsTests { +class CollectionUtilsTest { @Test - public void distinctByKeysTest() { + void distinctByKeysTest() { // Test with distinct keys Predicate predicate = CollectionUtils.distinctByKeys(String::length); assertTrue(predicate.test("apple")); @@ -31,7 +30,7 @@ public void distinctByKeysTest() { } @Test - public void sortByValueTest() { + void sortByValueTest() { // Test with normal map Map map = new HashMap<>(); map.put("apple", 5); diff --git a/src/test/java/com/shortthirdman/primekit/essentials/DateUtilsTest.java b/src/test/java/com/shortthirdman/primekit/essentials/common/util/DateUtilsTest.java similarity index 92% rename from src/test/java/com/shortthirdman/primekit/essentials/DateUtilsTest.java rename to src/test/java/com/shortthirdman/primekit/essentials/common/util/DateUtilsTest.java index 3be1773..3250755 100644 --- a/src/test/java/com/shortthirdman/primekit/essentials/DateUtilsTest.java +++ b/src/test/java/com/shortthirdman/primekit/essentials/common/util/DateUtilsTest.java @@ -1,6 +1,4 @@ -package com.shortthirdman.primekit.essentials; - -import com.shortthirdman.primekit.essentials.common.util.DateUtils; +package com.shortthirdman.primekit.essentials.common.util; import org.junit.jupiter.api.Test; @@ -132,26 +130,26 @@ public void givenStartDate_givenEndDate_datesBetween() { @Test public void givenDateString_parseStrictly() { - LocalDate expectedValue1 = LocalDate.of(2019, 2, 27); + LocalDate expectedValue1 = LocalDate.of(2019, Month.FEBRUARY, 27); assertEquals(expectedValue1, DateUtils.strictParseDate("2019-02-27", "yyyy-MM-dd")); - LocalDate expectedValue2 = LocalDate.of(2019, 2, 28); + LocalDate expectedValue2 = LocalDate.of(2019, Month.FEBRUARY, 28); assertEquals(expectedValue2, DateUtils.strictParseDate("2019-02-28", "yyyy-MM-dd")); - LocalDate expectedValue3 = LocalDate.of(2019, 2, 29); + LocalDate expectedValue3 = LocalDate.of(2019, Month.FEBRUARY, 29); assertEquals(expectedValue3, DateUtils.strictParseDate("2019-02-29", "yyyy-MM-dd")); } @Test public void givenDateTimeString_parseStrictly() { - LocalDateTime expectedValue1 = LocalDateTime.of(2019, 2, 27, 11, 23, 56, 1234); - assertEquals(expectedValue1, DateUtils.strictParseDateTime("2019-02-27T11:23:56.1234", null)); + LocalDateTime expectedValue1 = LocalDateTime.of(2019, Month.FEBRUARY, 27, 11, 23, 56, 123400000); + assertEquals(expectedValue1, DateUtils.strictParseDateTime("2019-02-27'T'11:23:56.123400000", null)); - LocalDateTime expectedValue2 = LocalDateTime.of(2019, 2, 27, 11, 23, 56, 1234); - assertEquals(expectedValue2, DateUtils.strictParseDateTime("2019-02-28T11:23:56.1234", null)); + LocalDateTime expectedValue2 = LocalDateTime.of(2019, Month.FEBRUARY, 27, 11, 23, 56, 1234); + assertEquals(expectedValue2, DateUtils.strictParseDateTime("2019-02-28'T'11:23:56.1234", null)); - LocalDateTime expectedValue3 = LocalDateTime.of(2019, 2, 27, 11, 23, 56, 1234); - assertEquals(expectedValue3, DateUtils.strictParseDateTime("2019-02-29T11:23:56.1234", null)); + LocalDateTime expectedValue3 = LocalDateTime.of(2019, Month.FEBRUARY, 27, 11, 23, 56, 1234); + assertEquals(expectedValue3, DateUtils.strictParseDateTime("2019-02-29'T'11:23:56.1234", null)); } @Test diff --git a/src/test/java/com/shortthirdman/primekit/essentials/MathUtilsTests.java b/src/test/java/com/shortthirdman/primekit/essentials/common/util/MathUtilsTest.java similarity index 81% rename from src/test/java/com/shortthirdman/primekit/essentials/MathUtilsTests.java rename to src/test/java/com/shortthirdman/primekit/essentials/common/util/MathUtilsTest.java index 642bf4f..ed9fbc0 100644 --- a/src/test/java/com/shortthirdman/primekit/essentials/MathUtilsTests.java +++ b/src/test/java/com/shortthirdman/primekit/essentials/common/util/MathUtilsTest.java @@ -1,25 +1,27 @@ -package com.shortthirdman.primekit.essentials; +package com.shortthirdman.primekit.essentials.common.util; -import com.shortthirdman.primekit.essentials.common.util.MathUtils; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertThrows; -public class MathUtilsTests { +class MathUtilsTest { @Test void testVariance() { double[] array = {1, 2, 3, 4, 5}; int n = array.length; - assertEquals(2.5, MathUtils.variance(array, n)); + assertEquals(2.0, MathUtils.variance(array, n)); + assertNotEquals(2.5, MathUtils.variance(array, n)); } @Test void testStandardDeviation() { double[] array = {1, 2, 3, 4, 5}; int n = array.length; - assertEquals(1.5811388300841898, MathUtils.standardDeviation(array, n)); + assertEquals(1.4142135623730951, MathUtils.standardDeviation(array, n)); + assertNotEquals(1.5811388300841898, MathUtils.standardDeviation(array, n)); } @Test From 3e0f7801b5347f131fa18e5ae9a410c42794ec67 Mon Sep 17 00:00:00 2001 From: Swetank Mohanty Date: Fri, 9 May 2025 17:41:08 +0530 Subject: [PATCH 08/12] core(utils): Added new methods and their test cases --- .../essentials/common/util/StringUtils.java | 139 +++++++++++++++++- .../common/util/StringUtilsTest.java | 103 +++++++++++++ 2 files changed, 234 insertions(+), 8 deletions(-) create mode 100644 src/test/java/com/shortthirdman/primekit/essentials/common/util/StringUtilsTest.java diff --git a/src/main/java/com/shortthirdman/primekit/essentials/common/util/StringUtils.java b/src/main/java/com/shortthirdman/primekit/essentials/common/util/StringUtils.java index 1dacba3..20a69bc 100644 --- a/src/main/java/com/shortthirdman/primekit/essentials/common/util/StringUtils.java +++ b/src/main/java/com/shortthirdman/primekit/essentials/common/util/StringUtils.java @@ -6,6 +6,11 @@ import java.util.*; import java.util.stream.Collectors; +/** + * Utility class for string manipulation + * @author ShortThirdMan + * @version 1.0.0 + */ public final class StringUtils { private StringUtils() { @@ -21,6 +26,9 @@ private StringUtils() { * @return the camel-case converted text string */ public static String snakeToCamel(String text) { + if (text == null || text.isEmpty()) { + throw new IllegalArgumentException("Source text cannot be null or empty"); + } text = text.substring(0, 1).toUpperCase() + text.substring(1); while (text.contains(GenericConstants.UNDERSCORE.getValue())) { text = text.replaceFirst("_[a-z]", @@ -38,6 +46,9 @@ public static String snakeToCamel(String text) { * @return snake-case converted text string */ public static String camelToSnake(String text) { + if (text == null || text.isEmpty()) { + throw new IllegalArgumentException("Source text cannot be null or empty"); + } String regex = "([a-z])([A-Z]+)"; String replacement = "$1_$2"; text = text.replaceAll(regex, replacement).toLowerCase(); @@ -49,7 +60,7 @@ public static String camelToSnake(String text) { * * @param text the input string to convert * @param upper true if result snake cased string should be upper cased - * @return + * @return snake-case converted text string */ public static String camelToSnake(final String text, final boolean upper) { String ret = text.replaceAll("([A-Z]+)([A-Z][a-z])", "$1_$2").replaceAll("([a-z])([A-Z])", "$1_$2"); @@ -64,9 +75,9 @@ public static String camelToSnake(final String text, final boolean upper) { /** * Converts a delimited text string into list of string * - * @param delimitedText - * @param delimiter - * @return + * @param delimitedText the input delimited text string + * @param delimiter the delimiter used to split the text + * @return the list of strings */ public static List convertToList(String delimitedText, String delimiter) { List result = List.of(); @@ -82,6 +93,7 @@ public static List convertToList(String delimitedText, String delimiter) } /** + * Trims the input text and returns the trimmed value. * @param textValue the source input text to trim * @return the trimmed value */ @@ -135,7 +147,7 @@ public boolean isIsomorphic(String s, String t) { /** * Helper method to convert a byte[] array (such as a MsgId) to a hex string * - * @param array + * @param array the input array * @return hex string */ public static String arrayToHexString(byte[] array) { @@ -155,9 +167,9 @@ public static String arrayToHexString(byte[] array) { /** * Convert a byte[] array (such as a MsgId) to a hex string * - * @param array - * @param offset - * @param limit + * @param array the input array + * @param offset the offset size + * @param limit the limit size * @return hex string */ public static String arrayToHexString(byte[] array, int offset, int limit) { @@ -207,6 +219,13 @@ public static boolean containsNonAscii(String source) { return false; } + /** + * Convert ASCII to hex byte array + * @param src the source byte array + * @param len the length of source bytes + * @param padding the padding type length + * @return the converted hex byte array + */ public static byte[] asciiToHex(byte[] src, int len, int padding) { byte[] asc; @@ -229,6 +248,13 @@ public static byte[] asciiToHex(byte[] src, int len, int padding) { return bcd; } + /** + * Calculates the left partitioned byte array from source + * @param src the source byte array + * @param len the length of source bytes + * @param fill the fill byte character + * @return the left partitioned byte array from source + */ private static byte[] getLeftPartitionBytes(final byte[] src, final int len, final byte fill) { byte[] des = new byte[len]; @@ -246,6 +272,7 @@ private static byte[] getLeftPartitionBytes(final byte[] src, final int len, fin } /** + * Calculates the right partitioned byte array from source * @param src the source byte array * @param len the length of source bytes * @param fill the fill byte character @@ -287,4 +314,100 @@ private static byte convertByteToBCD(byte src) { return re; } + + /** + * Returns the first non-null and non-blank string from the given values. + * @param values the input arguments + * @return the first non-null and non-blank string + */ + public static String coalesce(String... values) { + return Arrays.stream(values) + .filter(s -> s != null && !s.isBlank()) + .findFirst() + .orElse(""); + } + + /** + * Joins a list of strings into a comma-separated string. + * @param items the input list of items + * @return the comma separated string + */ + public static String joinWithComma(List items) { + return items == null ? "" : String.join(", ", items); + } + + /** + * Wraps the given value with double quotes. + * @param value the input value + * @return the value wrapped with double quotes + */ + public static String wrapWithQuotes(String value) { + return "\"" + value + "\""; + } + + /** + * Wraps a nullable value into an {@link java.util.Optional}. + * @param value the input value + * @param the type of the value + * @return an {@link java.util.Optional} containing the value if it's not null, otherwise an empty Optional + */ + public static Optional asOptional(T value) { + return Optional.ofNullable(value); + } + + /** + * Checks if a string is a palindrome. + * @param input the input string + * @return true if the string is a palindrome, false otherwise + */ + public static boolean isPalindrome(String input) { + if (input == null) return false; + String clean = input.replaceAll("[^a-zA-Z0-9]", "").toLowerCase(); + return new StringBuilder(clean).reverse().toString().equals(clean); + } + + /** + * Generates a random alphanumeric string of the given length. + * @param length the length of the string to generate + * @return the generated random alphanumeric string + */ + public static String generateRandomAlphanumeric(int length) { + if (length <= 0) { + throw new IllegalArgumentException("Length must be greater than 0"); + } + + final String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + return new Random().ints(length, 0, chars.length()) + .mapToObj(chars::charAt) + .map(Object::toString) + .collect(Collectors.joining()); + } + + /** + * Checks whether a string is null or blank (empty or whitespace only). + * @param input the input string + * @return true if the string is null or blank, false otherwise + */ + public static boolean isNullOrBlank(String input) { + return input == null || input.isBlank(); + } + + /** + * Converts the first letter to uppercase and leaves the rest unchanged. + * @param input the input string + * @return the string with the first letter capitalized + */ + public static String capitalize(String input) { + if (isNullOrBlank(input)) return input; + return input.substring(0, 1).toUpperCase() + input.substring(1); + } + + /** + * Safely converts an object to a string, returning an empty string if null. + * @param obj the object to convert + * @return the string representation of the object, or an empty string if null + */ + public static String safeToString(Object obj) { + return Optional.ofNullable(obj).map(Object::toString).orElse(""); + } } diff --git a/src/test/java/com/shortthirdman/primekit/essentials/common/util/StringUtilsTest.java b/src/test/java/com/shortthirdman/primekit/essentials/common/util/StringUtilsTest.java new file mode 100644 index 0000000..b9c06f0 --- /dev/null +++ b/src/test/java/com/shortthirdman/primekit/essentials/common/util/StringUtilsTest.java @@ -0,0 +1,103 @@ +package com.shortthirdman.primekit.essentials.common.util; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class StringUtilsTest { + + @BeforeEach + void setUp() { + } + + @AfterEach + void tearDown() { + } + + @Test + void testSnakeToCamel() { + // Basic conversions + assertEquals("HelloWorld", StringUtils.snakeToCamel("hello_world")); + assertEquals("MyVariableName", StringUtils.snakeToCamel("my_variable_name")); + assertEquals("SnakeCaseExample", StringUtils.snakeToCamel("snake_case_example")); + + // Already camel case input + assertEquals("CamelCase", StringUtils.snakeToCamel("camelCase")); + + // Input with no underscores + assertEquals("Hello", StringUtils.snakeToCamel("hello")); + + // Input with leading underscore (should throw StringIndexOutOfBoundsException or incorrect behavior) + assertEquals("HelloWorld", StringUtils.snakeToCamel("_hello_world")); // Depending on intent, may need to handle this + + // All uppercase input + assertEquals("TestCase", StringUtils.snakeToCamel("test_case")); + assertEquals("XMLHttpRequest", StringUtils.snakeToCamel("x_m_l_http_request")); + + // Underscores at the end + assertEquals("Example_", StringUtils.snakeToCamel("example_")); // might throw or behave oddly + + // Multiple consecutive underscores + assertEquals("Multiple_ConsecutiveUnderscores", StringUtils.snakeToCamel("multiple__consecutive_underscores")); + + // Empty string + assertThrows(IllegalArgumentException.class, () -> StringUtils.snakeToCamel("")); + + // Single character + assertEquals("A", StringUtils.snakeToCamel("a")); + } + + @Test + void testCamelToSnake() { + // Basic conversions + assertEquals("hello_world", StringUtils.camelToSnake("HelloWorld")); + assertEquals("my_variable_name", StringUtils.camelToSnake("MyVariableName")); + assertEquals("snake_case_example", StringUtils.camelToSnake("SnakeCaseExample")); + + // Single word, no uppercase transitions + assertEquals("hello", StringUtils.camelToSnake("Hello")); + + // Mixed casing and acronyms + assertEquals("x_m_l_http_request", StringUtils.camelToSnake("XMLHttpRequest")); + assertEquals("get_u_r_l", StringUtils.camelToSnake("getURL")); + + // Lower camelCase + assertEquals("camel_case", StringUtils.camelToSnake("camelCase")); + + // All lowercase input + assertEquals("simple", StringUtils.camelToSnake("simple")); + + // Leading capital letter + assertEquals("a_test", StringUtils.camelToSnake("ATest")); + + // Edge cases: null and empty input + assertThrows(IllegalArgumentException.class, () -> StringUtils.camelToSnake(null)); + assertThrows(IllegalArgumentException.class, () -> StringUtils.camelToSnake("")); + + // Single character input + assertEquals("a", StringUtils.camelToSnake("A")); + assertEquals("b", StringUtils.camelToSnake("b")); + } + + @Test + void testGenerateRandomAlphanumeric() { + assertThrows(IllegalArgumentException.class, () -> StringUtils.generateRandomAlphanumeric(0)); + + // Test length of generated string + int length = 10; + String randomString = StringUtils.generateRandomAlphanumeric(length); + assertEquals(length, randomString.length()); + + // Test if the generated string contains only alphanumeric characters + assertTrue(randomString.matches("^[a-zA-Z0-9]+$")); + + // Test with different lengths + for (int i = 1; i <= 100; i++) { + String randomStr = StringUtils.generateRandomAlphanumeric(i); + assertEquals(i, randomStr.length()); + assertTrue(randomStr.matches("^[a-zA-Z0-9]+$")); + } + } +} \ No newline at end of file From 9ad08bb14807c2ee66614c7e69aecc5e635b19e7 Mon Sep 17 00:00:00 2001 From: Swetank Mohanty Date: Fri, 9 May 2025 17:42:19 +0530 Subject: [PATCH 09/12] core(utils): Added javadoc on methods with clear documentation --- .../essentials/common/CounterNode.java | 5 +++ .../essentials/common/util/ClassUtils.java | 18 +++++++++ .../common/util/CollectionUtils.java | 10 +++++ .../essentials/common/util/DateUtils.java | 6 +-- .../essentials/common/util/FileUtils.java | 38 +++++++++++++++++++ .../essentials/common/util/MathUtils.java | 10 +++++ .../essentials/common/util/NumberUtils.java | 26 +++++++++++++ .../essentials/common/util/SystemUtils.java | 19 +++++++--- 8 files changed, 124 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/shortthirdman/primekit/essentials/common/CounterNode.java b/src/main/java/com/shortthirdman/primekit/essentials/common/CounterNode.java index f584975..1071d65 100644 --- a/src/main/java/com/shortthirdman/primekit/essentials/common/CounterNode.java +++ b/src/main/java/com/shortthirdman/primekit/essentials/common/CounterNode.java @@ -3,6 +3,11 @@ import lombok.Getter; import lombok.Setter; +/** + * A class that represents a node in a tree structure with a count. + * @author ShortThirdMan + * @version 1.0.0 + */ @Getter @Setter public class CounterNode { diff --git a/src/main/java/com/shortthirdman/primekit/essentials/common/util/ClassUtils.java b/src/main/java/com/shortthirdman/primekit/essentials/common/util/ClassUtils.java index 1149eb2..aa14832 100644 --- a/src/main/java/com/shortthirdman/primekit/essentials/common/util/ClassUtils.java +++ b/src/main/java/com/shortthirdman/primekit/essentials/common/util/ClassUtils.java @@ -4,7 +4,14 @@ import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; +import java.util.Objects; +import java.util.Optional; +/** + * Utility class for class loading and resource management. + * @author ShortThirdMan + * @version 1.0.0 + */ public final class ClassUtils { private ClassUtils() { @@ -109,4 +116,15 @@ public static Class loadClass(String className, Class caller) throws Class } } } + + /** + * Safely casts an object using Java’s pattern matching. + * @param obj the object to cast + * @param type the class type to cast to + * @param the type of the object + * @return an Optional containing the cast object if successful, or an empty Optional if the cast fails + */ + public static Optional safeCast(Object obj, Class type) { + return (!Objects.isNull(obj) && type.isInstance(obj)) ? Optional.of(type.cast(obj)) : Optional.empty(); + } } diff --git a/src/main/java/com/shortthirdman/primekit/essentials/common/util/CollectionUtils.java b/src/main/java/com/shortthirdman/primekit/essentials/common/util/CollectionUtils.java index b4ee147..b6f0ab7 100644 --- a/src/main/java/com/shortthirdman/primekit/essentials/common/util/CollectionUtils.java +++ b/src/main/java/com/shortthirdman/primekit/essentials/common/util/CollectionUtils.java @@ -132,4 +132,14 @@ public static > Map sortByValue(Map the typed-data of items in collection + * @return the list of items + */ + public static List toListOrEmpty(List list) { + return list == null ? List.of() : list; + } } diff --git a/src/main/java/com/shortthirdman/primekit/essentials/common/util/DateUtils.java b/src/main/java/com/shortthirdman/primekit/essentials/common/util/DateUtils.java index 6a9128c..8a8797a 100644 --- a/src/main/java/com/shortthirdman/primekit/essentials/common/util/DateUtils.java +++ b/src/main/java/com/shortthirdman/primekit/essentials/common/util/DateUtils.java @@ -199,7 +199,7 @@ public static boolean isWeekend(final Date date) { * @return the final business day */ public static LocalDate addBusinessDays(LocalDate localDate, int days, List holidays) { - if (localDate == null || days <= 0 || holidays.isEmpty()) { + if (localDate == null || days <= 0) { //|| holidays.isEmpty() throw new IllegalArgumentException("Invalid method argument(s) " + "to addBusinessDays(" + localDate + "," + days + "," + holidays + ")"); } @@ -329,7 +329,7 @@ public static LocalDate strictParseDate(String dateValue, String formatPattern) } if (formatPattern == null || StringUtils.isBlank(formatPattern)) { - formatPattern = "uuuu-MM-dd"; + formatPattern = "yyyy-MM-dd"; } DateTimeFormatter dtf = DateTimeFormatter.ofPattern(formatPattern); @@ -351,7 +351,7 @@ public static LocalDateTime strictParseDateTime(String dateValue, String formatP } if (formatPattern == null || StringUtils.isBlank(formatPattern)) { - formatPattern = "uuuu-MM-dd'T'HH:mm:ss.SSSS"; + formatPattern = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSS"; } DateTimeFormatter dtf = DateTimeFormatter.ofPattern(formatPattern); diff --git a/src/main/java/com/shortthirdman/primekit/essentials/common/util/FileUtils.java b/src/main/java/com/shortthirdman/primekit/essentials/common/util/FileUtils.java index 798105e..291d365 100644 --- a/src/main/java/com/shortthirdman/primekit/essentials/common/util/FileUtils.java +++ b/src/main/java/com/shortthirdman/primekit/essentials/common/util/FileUtils.java @@ -8,6 +8,9 @@ import java.io.OutputStream; import java.nio.channels.FileChannel; import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.util.Optional; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; @@ -107,7 +110,9 @@ public static void copyFile(File source, File destination) throws IOException { } /** + * Removes a directory and all its contents. * @param directory the directory to delete + * @return true if the directory was deleted, false otherwise */ public static boolean removeDirectory(File directory) { boolean result = false; @@ -127,6 +132,7 @@ public static boolean removeDirectory(File directory) { } /** + * Cleans the directory by removing all files and subdirectories. * @param directory the directory to clean */ public static void cleanDirectory(File directory) { @@ -139,4 +145,36 @@ public static void cleanDirectory(File directory) { } } } + + /** + * Reads the content of a file into a string. + * @param path the path to the file + * @return the content of the file as a string + * @throws IOException if an I/O error occurs + */ + public static String readFileContent(Path path) throws IOException { + return Files.readString(path); + } + + /** + * Writes a string to a file. + * @param path the path to the file + * @param content the content to write to the file + * @throws IOException if an I/O error occurs + */ + public static void writeToFile(Path path, String content) throws IOException { + Files.writeString(path, content, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING); + } + + /** + * Extracts the file extension from a filename. + * @param filename the filename + * @return the file extension, or an empty string if there is no extension + */ + public static String getFileExtension(String filename) { + return Optional.ofNullable(filename) + .filter(f -> f.contains(".")) + .map(f -> f.substring(f.lastIndexOf('.') + 1)) + .orElse(""); + } } diff --git a/src/main/java/com/shortthirdman/primekit/essentials/common/util/MathUtils.java b/src/main/java/com/shortthirdman/primekit/essentials/common/util/MathUtils.java index 1cefdc9..862fbf8 100644 --- a/src/main/java/com/shortthirdman/primekit/essentials/common/util/MathUtils.java +++ b/src/main/java/com/shortthirdman/primekit/essentials/common/util/MathUtils.java @@ -13,6 +13,10 @@ private MathUtils() { * @return */ public static double variance(double[] array, int n) { + if (array == null || array.length == 0) { + throw new IllegalArgumentException("array is null or empty"); + } + double sum = 0; for (int i = 0; i < n; i++) sum += array[i]; @@ -33,6 +37,9 @@ public static double variance(double[] array, int n) { * @return */ public static double standardDeviation(double[] array, int n) { + if (array == null || array.length == 0) { + throw new IllegalArgumentException("array is null or empty"); + } return Math.sqrt(variance(array, n)); } @@ -44,6 +51,9 @@ public static double standardDeviation(double[] array, int n) { * @return */ public static double average(double[] array, int n) { + if (array == null || array.length == 0) { + throw new IllegalArgumentException("array is null or empty"); + } double sum = 0; double finalsum = 0; for (double i : array) { diff --git a/src/main/java/com/shortthirdman/primekit/essentials/common/util/NumberUtils.java b/src/main/java/com/shortthirdman/primekit/essentials/common/util/NumberUtils.java index 0134a21..8daf31a 100644 --- a/src/main/java/com/shortthirdman/primekit/essentials/common/util/NumberUtils.java +++ b/src/main/java/com/shortthirdman/primekit/essentials/common/util/NumberUtils.java @@ -7,7 +7,13 @@ import java.text.DecimalFormatSymbols; import java.text.NumberFormat; import java.util.Locale; +import java.util.Optional; +/** + * Utility class for number formatting and manipulation. + * @author ShortThirdMan + * @version 1.0.0 + */ public final class NumberUtils { private NumberUtils() { @@ -151,4 +157,24 @@ public static String changeToRequiredDecimals(String bigDecimalValue, int precis return newFormattedString.toString(); } + + /** + * Rounds a double value to two decimal places. + * @param value the input value + * @return the rounded value + */ + public static double roundToTwoDecimals(double value) { + return Math.round(value * 100.0) / 100.0; + } + + /** + * Checks whether a string contains only digits. + * @param input the input string + * @return true if the string is numeric, false otherwise + */ + public static boolean isNumeric(String input) { + return Optional.ofNullable(input) + .map(s -> s.matches("\\d+")) + .orElse(false); + } } diff --git a/src/main/java/com/shortthirdman/primekit/essentials/common/util/SystemUtils.java b/src/main/java/com/shortthirdman/primekit/essentials/common/util/SystemUtils.java index c8014cc..4cd0ccc 100644 --- a/src/main/java/com/shortthirdman/primekit/essentials/common/util/SystemUtils.java +++ b/src/main/java/com/shortthirdman/primekit/essentials/common/util/SystemUtils.java @@ -3,6 +3,7 @@ import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; +import java.util.Optional; public final class SystemUtils { @@ -76,9 +77,8 @@ public static int getPid(int port) { * @return int */ private static int getPidWin(int port) { - String[] command = { "netstat", "-on" }; try { - Process netstat = Runtime.getRuntime().exec(command); + Process netstat = Runtime.getRuntime().exec(new String[]{"netstat", "-on"}); StringBuilder connectionList = new StringBuilder(); Reader reader = new InputStreamReader(netstat.getInputStream()); @@ -129,9 +129,8 @@ private static int getPidWin(int port) { * @return int */ private static int getPidLinux(int port) { - String[] command = { "netstat", "-anp" }; try { - Process netstat = Runtime.getRuntime().exec(command); + Process netstat = Runtime.getRuntime().exec(new String[]{"netstat", "-anp"}); StringBuilder connectionList = new StringBuilder(); Reader reader = new InputStreamReader(netstat.getInputStream()); @@ -150,7 +149,7 @@ private static int getPidLinux(int port) { int idx = connection.indexOf("/soffice.bin"); int idx2 = idx; while (Character.isDigit(connection.charAt(--idx2))) { - System.out.println(""); + System.out.println("idx2: " + idx2); } pid = connection.substring(idx2 + 1, idx); } @@ -166,4 +165,14 @@ private static int getPidLinux(int port) { return 0; } + + /** + * Fetches an environment variable or returns a default value. + * @param key the environment variable key + * @param defaultValue the default value to return if the key is not found + * @return the value of the environment variable or the default value + */ + public static String getEnv(String key, String defaultValue) { + return Optional.ofNullable(System.getenv(key)).orElse(defaultValue); + } } From daa7c89a28c3fecfd68a13485cb8a19110b559f6 Mon Sep 17 00:00:00 2001 From: Swetank Mohanty Date: Fri, 9 May 2025 17:55:44 +0530 Subject: [PATCH 10/12] devops(gha): Updated workflow for Maven CI with Java --- .github/workflows/maven.yml | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index eddddc6..45e1502 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -20,18 +20,15 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - name: Checkout sources + uses: actions/checkout@v4 + - name: Set up JDK 21 uses: actions/setup-java@v3 with: java-version: '21' distribution: 'temurin' cache: maven - - name: Build with Maven - run: | - cd primekit-essentials - mvn -B clean package -DskipTests - # Optional: Uploads the full dependency graph to GitHub to improve the quality of Dependabot alerts this repository can receive - #- name: Update dependency graph - # uses: advanced-security/maven-dependency-submission-action@571e99aab1055c2e71a1e2309b9691de18d6b7d6 + - name: Build with Maven + run: mvn -B clean package -DskipTests \ No newline at end of file From 719be518dadf76cb42a64cab9cddb6f166596421 Mon Sep 17 00:00:00 2001 From: Swetank Mohanty Date: Tue, 5 Aug 2025 23:18:35 +0530 Subject: [PATCH 11/12] core: Added and updated enums, utilities, annotations, and validators --- .github/workflows/auto-assign.yml | 20 ++++ LICENSE | 2 +- pom.xml | 97 ++++++++++++++++--- .../primekit/essentials/common/YearWeek.java | 5 + .../essentials/common/enums/Directions.java | 24 +++++ .../essentials/common/enums/Seasons.java | 19 ++++ .../essentials/common/util/HttpUtils.java | 33 +++++++ .../essentials/core/AsyncRequestMerger.java | 82 ++++++++++++++++ .../essentials/core/CachedRequestMerger.java | 47 +++++++++ .../core/FastFailingRequestMerger.java | 86 ++++++++++++++++ .../essentials/core/GenericRequestMerger.java | 77 +++++++++++++++ .../essentials/core/RequestMerger.java | 15 +++ .../generics/annotations/Email.java | 15 +++ .../generics/annotations/ProtectData.java | 19 ++++ .../generics/annotations/Required.java | 15 +++ .../processor/ProtectDataSerializer.java | 56 +++++++++++ .../generics/validator/Validator.java | 4 + .../generics/webmvc/FormBinder.java | 78 +++++++++++++++ .../essentials/core/RequestMergerTest.java | 39 ++++++++ 19 files changed, 720 insertions(+), 13 deletions(-) create mode 100644 .github/workflows/auto-assign.yml create mode 100644 src/main/java/com/shortthirdman/primekit/essentials/common/enums/Directions.java create mode 100644 src/main/java/com/shortthirdman/primekit/essentials/common/enums/Seasons.java create mode 100644 src/main/java/com/shortthirdman/primekit/essentials/common/util/HttpUtils.java create mode 100644 src/main/java/com/shortthirdman/primekit/essentials/core/AsyncRequestMerger.java create mode 100644 src/main/java/com/shortthirdman/primekit/essentials/core/CachedRequestMerger.java create mode 100644 src/main/java/com/shortthirdman/primekit/essentials/core/FastFailingRequestMerger.java create mode 100644 src/main/java/com/shortthirdman/primekit/essentials/core/GenericRequestMerger.java create mode 100644 src/main/java/com/shortthirdman/primekit/essentials/core/RequestMerger.java create mode 100644 src/main/java/com/shortthirdman/primekit/essentials/generics/annotations/Email.java create mode 100644 src/main/java/com/shortthirdman/primekit/essentials/generics/annotations/ProtectData.java create mode 100644 src/main/java/com/shortthirdman/primekit/essentials/generics/annotations/Required.java create mode 100644 src/main/java/com/shortthirdman/primekit/essentials/generics/annotations/processor/ProtectDataSerializer.java create mode 100644 src/main/java/com/shortthirdman/primekit/essentials/generics/validator/Validator.java create mode 100644 src/main/java/com/shortthirdman/primekit/essentials/generics/webmvc/FormBinder.java create mode 100644 src/test/java/com/shortthirdman/primekit/essentials/core/RequestMergerTest.java diff --git a/.github/workflows/auto-assign.yml b/.github/workflows/auto-assign.yml new file mode 100644 index 0000000..a7f0380 --- /dev/null +++ b/.github/workflows/auto-assign.yml @@ -0,0 +1,20 @@ +name: Auto Assign +on: + issues: + types: [opened, reopened] + pull_request: + types: [opened, reopened] +jobs: + run: + runs-on: ubuntu-latest + permissions: + issues: write + pull-requests: write + steps: + - name: 'Auto-assign issue' + uses: pozil/auto-assign-issue@v2 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + assignees: shortthirdman + numOfAssignee: 1 + allowSelfAssign: true \ No newline at end of file diff --git a/LICENSE b/LICENSE index 261eeb9..1cf8c4f 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright [yyyy] [name of copyright owner] + Copyright 2025 ShortThirdMan Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pom.xml b/pom.xml index d0c463c..a27b05a 100644 --- a/pom.xml +++ b/pom.xml @@ -11,20 +11,24 @@ 2025 - 1.8 + true + shortthirdman-org/PrimeKit + [11,24) UTF-8 - 1.8 - 1.8 + ${java.version} + ${java.version} 21 1.18.32 0.12.6 6.2.5 3.2.5 - 2.15.4 + 2.18.4 4.0.2 - + 42. 5.6.10.Final - 5.11.0 + 5.12.0 + 2.3.0 + 32.1.3-jre 42.7.3 5.10.2 3.19.0 @@ -158,6 +162,18 @@ spring-data-commons ${spring-data.version} + + + io.github.resilience4j + resilience4j-circuitbreaker + ${resilience4j.version} + true + + + com.google.guava + guava + ${guava.version} + org.postgresql @@ -214,6 +230,11 @@ jackson-annotations ${fasterxml-jackson.version} + + com.fasterxml.jackson.core + jackson-databind + ${fasterxml-jackson.version} + org.apache.commons @@ -247,7 +268,7 @@ org.junit.jupiter junit-jupiter-engine - ${junit-jupiter.version} + test @@ -266,8 +287,7 @@ primekit-essentials-${project.version} - - + maven-resources-plugin 3.3.1 @@ -280,6 +300,13 @@ UTF-8 ${java.version} ${java.version} + + + org.projectlombok + lombok + ${lombok.version} + + @@ -287,7 +314,31 @@ 3.3.0 true + 1 + ${project.build.sourceEncoding} + brief + true + + + junit.jupiter.conditions.deactivate = * + junit.jupiter.extensions.autodetection.enabled = true + junit.jupiter.testinstance.lifecycle.default = per_class + junit.jupiter.execution.parallel.enabled = true + + + + + me.fabriciorby + maven-surefire-junit5-tree-reporter + 1.2.1 + + + org.apache.maven.surefire + surefire-junit-platform + 3.0.0 + + maven-jar-plugin @@ -301,16 +352,32 @@ maven-deploy-plugin 3.1.2 + + org.apache.maven.plugins + maven-failsafe-plugin + 3.5.3 + + true + true + + org.apache.maven.plugins maven-source-plugin 3.2.1 + + primekit-essentials-${project.version} + true + + ${build.timestamp} + attach-sources install jar-no-fork + test-jar-no-fork @@ -338,18 +405,24 @@ GenerateGitChangelog generate-sources + semantic-version git-changelog changelog.mustache + true -([^-]+?)$ CHANGELOG.md - false + ${isCI} + - - + diff --git a/src/main/java/com/shortthirdman/primekit/essentials/common/YearWeek.java b/src/main/java/com/shortthirdman/primekit/essentials/common/YearWeek.java index ab26b18..fe13aa3 100644 --- a/src/main/java/com/shortthirdman/primekit/essentials/common/YearWeek.java +++ b/src/main/java/com/shortthirdman/primekit/essentials/common/YearWeek.java @@ -1,5 +1,8 @@ package com.shortthirdman.primekit.essentials.common; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; + import java.text.MessageFormat; import java.time.DateTimeException; import java.time.LocalDate; @@ -25,6 +28,8 @@ public static YearWeek from(TemporalAccessor temporal) { } } + @NotNull + @Contract(pure = true) @Override public String toString() { return MessageFormat.format("{0}-{1}", year, week); diff --git a/src/main/java/com/shortthirdman/primekit/essentials/common/enums/Directions.java b/src/main/java/com/shortthirdman/primekit/essentials/common/enums/Directions.java new file mode 100644 index 0000000..cfea342 --- /dev/null +++ b/src/main/java/com/shortthirdman/primekit/essentials/common/enums/Directions.java @@ -0,0 +1,24 @@ +package com.shortthirdman.primekit.essentials.common.enums; + +import lombok.Getter; + +@Getter +public enum Directions { + + EAST("East", "E"), + NORTH("North", "N"), + NORTH_EAST("North-East", "NE"), + NORTH_WEST("North-West", "NW"), + SOUTH("South", "S"), + SOUTH_EAST("South-East", "SE"), + SOUTH_WEST("South-West", "SW"), + WEST("West", "SW"); + + private final String name; + private final String symbol; + + Directions(String name, String symbol) { + this.name = name; + this.symbol = symbol; + } +} diff --git a/src/main/java/com/shortthirdman/primekit/essentials/common/enums/Seasons.java b/src/main/java/com/shortthirdman/primekit/essentials/common/enums/Seasons.java new file mode 100644 index 0000000..c1717e8 --- /dev/null +++ b/src/main/java/com/shortthirdman/primekit/essentials/common/enums/Seasons.java @@ -0,0 +1,19 @@ +package com.shortthirdman.primekit.essentials.common.enums; + +import lombok.Getter; + +@Getter +public enum Seasons { + + WINTER("Winter"), + SPRING("Spring"), + SUMMER("Summer"), + FALL("Fall"), + AUTUMN("Autumn"); + + private final String name; + + Seasons(String name) { + this.name = name; + } +} diff --git a/src/main/java/com/shortthirdman/primekit/essentials/common/util/HttpUtils.java b/src/main/java/com/shortthirdman/primekit/essentials/common/util/HttpUtils.java new file mode 100644 index 0000000..2a952ca --- /dev/null +++ b/src/main/java/com/shortthirdman/primekit/essentials/common/util/HttpUtils.java @@ -0,0 +1,33 @@ +package com.shortthirdman.primekit.essentials.common.util; + +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; + +public final class HttpUtils { + + private HttpUtils() {} + + private static final HttpClient client = HttpClient.newBuilder() + .version(HttpClient.Version.HTTP_2) + .build(); + + public static String get(String url) throws IOException, InterruptedException { + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create(url)) + .GET() + .build(); + return client.send(request, HttpResponse.BodyHandlers.ofString()).body(); + } + + public static String post(String url, String jsonBody) throws IOException, InterruptedException { + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create(url)) + .header("Content-Type", "application/json") + .POST(HttpRequest.BodyPublishers.ofString(jsonBody)) + .build(); + return client.send(request, HttpResponse.BodyHandlers.ofString()).body(); + } +} diff --git a/src/main/java/com/shortthirdman/primekit/essentials/core/AsyncRequestMerger.java b/src/main/java/com/shortthirdman/primekit/essentials/core/AsyncRequestMerger.java new file mode 100644 index 0000000..d9b5de2 --- /dev/null +++ b/src/main/java/com/shortthirdman/primekit/essentials/core/AsyncRequestMerger.java @@ -0,0 +1,82 @@ +package com.shortthirdman.primekit.essentials.core; + +import java.util.*; +import java.util.concurrent.*; +import java.util.function.Function; + +public class AsyncRequestMerger implements RequestMerger { + + private final ConcurrentHashMap>> pendingRequests = new ConcurrentHashMap<>(); + private final List keyQueue = Collections.synchronizedList(new ArrayList<>()); + private final Function, Map> batchFunction; + private final long windowTimeMillis; + private final int maxBatchSize; + private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); + private final ExecutorService batchExecutor = Executors.newFixedThreadPool(2); + private final Semaphore backpressure = new Semaphore(5); + + public AsyncRequestMerger(Function, Map> batchFunction, long windowTimeMillis, int maxBatchSize) { + this.batchFunction = batchFunction; + this.windowTimeMillis = windowTimeMillis; + this.maxBatchSize = maxBatchSize; + } + + @Override + public CompletableFuture> get(K key) { + CompletableFuture> future = new CompletableFuture<>(); + CompletableFuture> existingFuture = pendingRequests.putIfAbsent(key, future); + if (existingFuture != null) { + return existingFuture; // Return existing future if key is already queued + } + synchronized (keyQueue) { + keyQueue.add(key); + if (keyQueue.size() == 1) { + scheduler.schedule(this::processBatch, windowTimeMillis, TimeUnit.MILLISECONDS); + } else if (keyQueue.size() >= maxBatchSize) { + processBatch(); + } + } + return future; + } + + private void processBatch() { + List batch; + synchronized (keyQueue) { + if (keyQueue.isEmpty()) return; + batch = new ArrayList<>(keyQueue); + keyQueue.clear(); + } + try { + backpressure.acquire(); + batchExecutor.submit(() -> { + Map results = null; + try { + results = batchFunction.apply(batch); + for (K key : batch) { + CompletableFuture> future = pendingRequests.remove(key); + if (future != null) { + future.complete(Optional.ofNullable(results.get(key))); + } + } + } catch (Exception e) { + for (K key : batch) { + CompletableFuture> future = pendingRequests.remove(key); + if (future != null) { + future.completeExceptionally(e); + } + } + } finally { + backpressure.release(); + } + }); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + + @Override + public void shutdown() { + scheduler.shutdown(); + batchExecutor.shutdown(); + } +} diff --git a/src/main/java/com/shortthirdman/primekit/essentials/core/CachedRequestMerger.java b/src/main/java/com/shortthirdman/primekit/essentials/core/CachedRequestMerger.java new file mode 100644 index 0000000..c8c952f --- /dev/null +++ b/src/main/java/com/shortthirdman/primekit/essentials/core/CachedRequestMerger.java @@ -0,0 +1,47 @@ +package com.shortthirdman.primekit.essentials.core; + +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; +import java.util.function.Function; + +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; + +/** + * @param the key class bean + * @param the value class + */ +public class CachedRequestMerger implements RequestMerger { + + private final GenericRequestMerger merger; + private final LoadingCache> cache; + + public CachedRequestMerger(long windowTimeMillis, int maxBatchSize, Function, Map> batchFunction) { + this.merger = new GenericRequestMerger<>(windowTimeMillis, maxBatchSize, batchFunction); + this.cache = CacheBuilder.newBuilder() + .maximumSize(1000) + .expireAfterWrite(10, TimeUnit.MINUTES) + .build(CacheLoader.from(key -> merger.get(key).join())); + } + + @Override + public CompletableFuture> get(K key) { + Optional cached = cache.getIfPresent(key); + if (!Objects.isNull(cached) && cached.isPresent()) { + return CompletableFuture.completedFuture(cached); + } + return merger.get(key).whenComplete((result, ex) -> { + if (ex == null) cache.put(key, result); + }); + } + + @Override + public void shutdown() { + merger.shutdown(); + } +} diff --git a/src/main/java/com/shortthirdman/primekit/essentials/core/FastFailingRequestMerger.java b/src/main/java/com/shortthirdman/primekit/essentials/core/FastFailingRequestMerger.java new file mode 100644 index 0000000..bf981f5 --- /dev/null +++ b/src/main/java/com/shortthirdman/primekit/essentials/core/FastFailingRequestMerger.java @@ -0,0 +1,86 @@ +package com.shortthirdman.primekit.essentials.core; + +import io.github.resilience4j.circuitbreaker.CircuitBreaker; +import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig; + +import java.util.*; +import java.util.concurrent.*; +import java.util.function.Function; + +public class FastFailingRequestMerger implements RequestMerger { + + private final ConcurrentHashMap>> pendingRequests = new ConcurrentHashMap<>(); + private final List keyQueue = Collections.synchronizedList(new ArrayList<>()); + private final Function, Map> batchFunction; + private final long windowTimeMillis; + private final int maxBatchSize; + private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); + private final ExecutorService batchExecutor = Executors.newFixedThreadPool(2); + private final Semaphore backpressure = new Semaphore(5); + private final CircuitBreaker circuitBreaker; + + public FastFailingRequestMerger(long windowTimeMillis, int maxBatchSize, Function, Map> batchFunction) { + this.windowTimeMillis = windowTimeMillis; + this.maxBatchSize = maxBatchSize; + this.batchFunction = batchFunction; + this.circuitBreaker = CircuitBreaker.of("requestMerger", CircuitBreakerConfig.ofDefaults()); + } + + @Override + public CompletableFuture> get(K key) { + CompletableFuture> future = new CompletableFuture<>(); + CompletableFuture> existingFuture = pendingRequests.putIfAbsent(key, future); + if (existingFuture != null) { + return existingFuture; // Return existing future if key is already queued + } + synchronized (keyQueue) { + keyQueue.add(key); + if (keyQueue.size() == 1) { + scheduler.schedule(this::processBatch, windowTimeMillis, TimeUnit.MILLISECONDS); + } else if (keyQueue.size() >= maxBatchSize) { + processBatch(); + } + } + return future; + } + + @Override + public void shutdown() { + scheduler.shutdown(); + circuitBreaker.reset(); + } + + private void processBatch() { + List batch; + synchronized (keyQueue) { + if (keyQueue.isEmpty()) return; + batch = new ArrayList<>(keyQueue); + keyQueue.clear(); + } + try { + backpressure.acquire(); + batchExecutor.submit(() -> { + try { + Map results = circuitBreaker.executeSupplier(() -> batchFunction.apply(batch)); + for (K key : batch) { + CompletableFuture> future = pendingRequests.remove(key); + if (future != null) { + future.complete(Optional.ofNullable(results.get(key))); + } + } + } catch (Exception e) { + for (K key : batch) { + CompletableFuture> future = pendingRequests.remove(key); + if (future != null) { + future.completeExceptionally(e); + } + } + } finally { + backpressure.release(); + } + }); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } +} diff --git a/src/main/java/com/shortthirdman/primekit/essentials/core/GenericRequestMerger.java b/src/main/java/com/shortthirdman/primekit/essentials/core/GenericRequestMerger.java new file mode 100644 index 0000000..92b6898 --- /dev/null +++ b/src/main/java/com/shortthirdman/primekit/essentials/core/GenericRequestMerger.java @@ -0,0 +1,77 @@ +package com.shortthirdman.primekit.essentials.core; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.function.Function; + +public class GenericRequestMerger implements RequestMerger { + + private final ConcurrentHashMap>> pendingRequests = new ConcurrentHashMap<>(); + private final List keyQueue = Collections.synchronizedList(new ArrayList<>()); + private final Function, Map> batchFunction; + private final long windowTimeMillis; + private final int maxBatchSize; + private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); + + public GenericRequestMerger(long windowTimeMillis, int maxBatchSize, Function, Map> batchFunction) { + this.windowTimeMillis = windowTimeMillis; + this.maxBatchSize = maxBatchSize; + this.batchFunction = batchFunction; + } + + @Override + public CompletableFuture> get(K key) { + CompletableFuture> future = new CompletableFuture<>(); + CompletableFuture> existingFuture = pendingRequests.putIfAbsent(key, future); + if (existingFuture != null) { + return existingFuture; // Return existing future if key is already queued + } + synchronized (keyQueue) { + keyQueue.add(key); + if (keyQueue.size() == 1) { + scheduler.schedule(this::processBatch, windowTimeMillis, TimeUnit.MILLISECONDS); + } else if (keyQueue.size() >= maxBatchSize) { + processBatch(); + } + } + return future; + } + + private void processBatch() { + List batch; + synchronized (keyQueue) { + if (keyQueue.isEmpty()) return; + batch = new ArrayList<>(keyQueue); + keyQueue.clear(); + } + try { + Map results = batchFunction.apply(batch); + for (K key : batch) { + CompletableFuture> future = pendingRequests.remove(key); + if (future != null) { + future.complete(Optional.ofNullable(results.get(key))); + } + } + } catch (Exception e) { + for (K key : batch) { + CompletableFuture> future = pendingRequests.remove(key); + if (future != null) { + future.completeExceptionally(e); + } + } + } + } + + @Override + public void shutdown() { + scheduler.shutdown(); + } +} diff --git a/src/main/java/com/shortthirdman/primekit/essentials/core/RequestMerger.java b/src/main/java/com/shortthirdman/primekit/essentials/core/RequestMerger.java new file mode 100644 index 0000000..afbaa6a --- /dev/null +++ b/src/main/java/com/shortthirdman/primekit/essentials/core/RequestMerger.java @@ -0,0 +1,15 @@ +package com.shortthirdman.primekit.essentials.core; + +import java.util.Optional; +import java.util.concurrent.CompletableFuture; + +public interface RequestMerger { + + /** + * @param key the key class + * @return + */ + CompletableFuture> get(K key); + + void shutdown(); +} diff --git a/src/main/java/com/shortthirdman/primekit/essentials/generics/annotations/Email.java b/src/main/java/com/shortthirdman/primekit/essentials/generics/annotations/Email.java new file mode 100644 index 0000000..46d1e4c --- /dev/null +++ b/src/main/java/com/shortthirdman/primekit/essentials/generics/annotations/Email.java @@ -0,0 +1,15 @@ +package com.shortthirdman.primekit.essentials.generics.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @author ShortThirdMan + * @version 1.0.0 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface Email { +} diff --git a/src/main/java/com/shortthirdman/primekit/essentials/generics/annotations/ProtectData.java b/src/main/java/com/shortthirdman/primekit/essentials/generics/annotations/ProtectData.java new file mode 100644 index 0000000..5be3cd0 --- /dev/null +++ b/src/main/java/com/shortthirdman/primekit/essentials/generics/annotations/ProtectData.java @@ -0,0 +1,19 @@ +package com.shortthirdman.primekit.essentials.generics.annotations; + +import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.shortthirdman.primekit.essentials.generics.annotations.processor.ProtectDataSerializer; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@JacksonAnnotationsInside +@JsonSerialize(using = ProtectDataSerializer.class) +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface ProtectData { + + String[] allowedRoles() default {"ADMIN"}; +} diff --git a/src/main/java/com/shortthirdman/primekit/essentials/generics/annotations/Required.java b/src/main/java/com/shortthirdman/primekit/essentials/generics/annotations/Required.java new file mode 100644 index 0000000..c01ca96 --- /dev/null +++ b/src/main/java/com/shortthirdman/primekit/essentials/generics/annotations/Required.java @@ -0,0 +1,15 @@ +package com.shortthirdman.primekit.essentials.generics.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @author ShortThirdMan + * @version 1.0.0 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface Required { +} diff --git a/src/main/java/com/shortthirdman/primekit/essentials/generics/annotations/processor/ProtectDataSerializer.java b/src/main/java/com/shortthirdman/primekit/essentials/generics/annotations/processor/ProtectDataSerializer.java new file mode 100644 index 0000000..c798103 --- /dev/null +++ b/src/main/java/com/shortthirdman/primekit/essentials/generics/annotations/processor/ProtectDataSerializer.java @@ -0,0 +1,56 @@ +package com.shortthirdman.primekit.essentials.generics.annotations.processor; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.BeanProperty; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.ser.ContextualSerializer; +import com.fasterxml.jackson.databind.ser.std.StdSerializer; +import com.shortthirdman.primekit.essentials.generics.annotations.ProtectData; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; + +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +/** + * + */ +public class ProtectDataSerializer extends StdSerializer implements ContextualSerializer { + + private String[] allowedRoles; + + public ProtectDataSerializer(String[] allowedRoles) { + this(); + this.allowedRoles = allowedRoles; + } + + public ProtectDataSerializer() { + super(Object.class); + } + + @Override + public JsonSerializer createContextual(SerializerProvider serializerProvider, BeanProperty beanProperty) throws JsonMappingException { + Optional annotation = Optional.ofNullable(beanProperty).map(prop -> prop.getAnnotation(ProtectData.class)); + return new ProtectDataSerializer(annotation.map(ProtectData::allowedRoles).orElse(new String[] {"ADMIN"})); + } + + @Override + public void serialize(Object value, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { + SecurityContext securityContext = SecurityContextHolder.getContext(); + Authentication authentication = securityContext.getAuthentication(); + String piiData = value.toString(); + if (authentication != null) { + final List allowedRolesList = Arrays.asList(this.allowedRoles); + long count = authentication.getAuthorities().stream().filter(ga -> allowedRolesList.contains(ga.getAuthority().substring(5))).count(); + if (count == 0) { + piiData = piiData.replaceAll("\\w(?=\\w{4})", "x"); + } + } + jsonGenerator.writeString(piiData); + } +} diff --git a/src/main/java/com/shortthirdman/primekit/essentials/generics/validator/Validator.java b/src/main/java/com/shortthirdman/primekit/essentials/generics/validator/Validator.java new file mode 100644 index 0000000..2cbb965 --- /dev/null +++ b/src/main/java/com/shortthirdman/primekit/essentials/generics/validator/Validator.java @@ -0,0 +1,4 @@ +package com.shortthirdman.primekit.essentials.generics.validator; + +public final class Validator { +} diff --git a/src/main/java/com/shortthirdman/primekit/essentials/generics/webmvc/FormBinder.java b/src/main/java/com/shortthirdman/primekit/essentials/generics/webmvc/FormBinder.java new file mode 100644 index 0000000..1437b42 --- /dev/null +++ b/src/main/java/com/shortthirdman/primekit/essentials/generics/webmvc/FormBinder.java @@ -0,0 +1,78 @@ +package com.shortthirdman.primekit.essentials.generics.webmvc; + +import com.shortthirdman.primekit.essentials.generics.annotations.Email; +import com.shortthirdman.primekit.essentials.generics.annotations.Required; + +import javax.servlet.http.HttpServletRequest; +import javax.xml.bind.ValidationException; +import java.lang.reflect.Field; + +/** + * @author ShortThirdMan + * @version 1.0.0 + */ +public final class FormBinder { + + private FormBinder() {} + + /** + * @param request the {@link HttpServletRequest} object + * @param clazz the {@link Class} + * @param the generic datatype + * @return the instance + * @throws Exception + */ + public static T bind(HttpServletRequest request, Class clazz) throws Exception { + T instance = clazz.getDeclaredConstructor().newInstance(); + for (Field field : clazz.getDeclaredFields()) { + field.setAccessible(true); + String value = request.getParameter(field.getName()); + + if (value == null) continue; + + Class type = field.getType(); + + if (type == String.class) { + field.set(instance, value); + } else if (type == int.class || type == Integer.class) { + field.set(instance, Integer.parseInt(value)); + } else if (type == boolean.class || type == Boolean.class) { + field.setBoolean(instance, "on".equalsIgnoreCase(value)); + field.set(instance, "on".equalsIgnoreCase(value) || "true".equalsIgnoreCase(value)); + } else if (type == double.class || type == Double.class) { + field.set(instance, Double.parseDouble(value)); + } else { + field.set(instance, value); + } + } + return instance; + } + + /** + * @param obj the object to validate + * @throws ValidationException + */ + public static void validate(Object obj) throws ValidationException { + for (Field field : obj.getClass().getDeclaredFields()) { + field.setAccessible(true); + Object value; + try { + value = field.get(obj); + } catch (IllegalAccessException e) { + continue; + } + + if (field.isAnnotationPresent(Required.class)) { + if (value == null || (value instanceof String s && s.trim().isEmpty())) { + throw new ValidationException(field.getName() + " is required"); + } + } + + if (field.isAnnotationPresent(Email.class)) { + if (value instanceof String s && !s.contains("@")) { + throw new ValidationException(field.getName() + " must be a valid email"); + } + } + } + } +} diff --git a/src/test/java/com/shortthirdman/primekit/essentials/core/RequestMergerTest.java b/src/test/java/com/shortthirdman/primekit/essentials/core/RequestMergerTest.java new file mode 100644 index 0000000..5c5259c --- /dev/null +++ b/src/test/java/com/shortthirdman/primekit/essentials/core/RequestMergerTest.java @@ -0,0 +1,39 @@ +package com.shortthirdman.primekit.essentials.core; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.function.Function; + +class RequestMergerTest { + + @BeforeEach + void setUp() { + } + + @Test + void testRequestMerger() { + Function, Map> batchFunction = ids -> { + Map results = new HashMap<>(); + for (Long id : ids) { + results.put(id, "User-" + id); + } + return results; + }; + GenericRequestMerger merger = new GenericRequestMerger<>(20, 3, batchFunction); + List>> futures = new ArrayList<>(); + + // Submit requests + for (long i = 1; i <= 5; i++) { + long finalI = i; + futures.add(merger.get(i).thenApply(result -> { + System.out.println("Result for " + finalI + ": " + result.orElse("Not found") + " 📦"); + return result; + })); + } + CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join(); + merger.shutdown(); + } +} \ No newline at end of file From c937e9b6ccd07992b0f4057fdab8d83fe2ac23c5 Mon Sep 17 00:00:00 2001 From: Swetank Mohanty Date: Mon, 8 Sep 2025 19:48:53 +0530 Subject: [PATCH 12/12] core(utils): Added utility class for methods related to CompletableFuture --- .../common/util/CompletableFutureUtils.java | 103 ++++++++++++++++++ .../util/CompletableFutureUtilsTest.java | 63 +++++++++++ 2 files changed, 166 insertions(+) create mode 100644 src/main/java/com/shortthirdman/primekit/essentials/common/util/CompletableFutureUtils.java create mode 100644 src/test/java/com/shortthirdman/primekit/essentials/common/util/CompletableFutureUtilsTest.java diff --git a/src/main/java/com/shortthirdman/primekit/essentials/common/util/CompletableFutureUtils.java b/src/main/java/com/shortthirdman/primekit/essentials/common/util/CompletableFutureUtils.java new file mode 100644 index 0000000..b92c4ca --- /dev/null +++ b/src/main/java/com/shortthirdman/primekit/essentials/common/util/CompletableFutureUtils.java @@ -0,0 +1,103 @@ +package com.shortthirdman.primekit.essentials.common.util; + +import org.jetbrains.annotations.NotNull; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Future; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.function.BiConsumer; + +/** + * A utility class to add JDK 9+ timeout functionality to CompletableFuture in JDK. + * Inspired by JDK 9's CompletableFuture implementation. + * + * @author ShortThirdMan + */ +public final class CompletableFutureUtils { + + private CompletableFutureUtils() {} + + /** + * If not already completed, causes this CompletableFuture to be + * completed exceptionally with a {@link TimeoutException} after the + * given timeout. + * + * @param future the CompletableFuture to apply the timeout to + * @param timeout how long to wait before completing exceptionally + * @param unit the time unit of the timeout argument + * @return the original CompletableFuture + */ + public static CompletableFuture orTimeout(CompletableFuture future, long timeout, TimeUnit unit) { + if (unit == null) { + throw new NullPointerException("Time unit cannot be null"); + } + if (future == null) { + throw new NullPointerException("CompletableFuture cannot be null"); + } + // If the future is already done, just return it. + if (future.isDone()) { + return future; + } + // Schedule a task to complete the future exceptionally after the timeout. + // The Canceller will cancel this scheduled task if the future completes normally. + return future.whenComplete(new Canceller(Delayer.delay(new Timeout(future), timeout, unit))); + } + + /** + * Inner class to handle the actual timeout logic + */ + static final class Timeout implements Runnable { + final CompletableFuture future; + Timeout(CompletableFuture future) { + this.future = future; + } + public void run() { + if (future != null && !future.isDone()) { + future.completeExceptionally(new TimeoutException()); + } + } + } + + /** + * Inner class to handle cancellation of the timeout task + */ + static final class Canceller implements BiConsumer { + final Future future; + Canceller(Future future) { + this.future = future; + } + public void accept(Object ignore, Throwable ex) { + // If the original future completed (ex is null) and the timeout task + // hasn't run yet, cancel the timeout task. + if (ex == null && future != null && !future.isDone()) { + future.cancel(false); + } + } + } + + /** + * Singleton delayed scheduler + */ + static final class Delayer { + static ScheduledFuture delay(Runnable command, long delay, TimeUnit unit) { + return delayer.schedule(command, delay, unit); + } + private static final ScheduledThreadPoolExecutor delayer; + static { + delayer = new ScheduledThreadPoolExecutor(1, new DaemonThreadFactory()); + delayer.setRemoveOnCancelPolicy(true); + } + static final class DaemonThreadFactory implements ThreadFactory { + public Thread newThread(@NotNull Runnable r) { + Thread t = new Thread(r); + t.setDaemon(true); + t.setName("CompletableFutureUtilsDelayScheduler"); + return t; + } + } + } +} diff --git a/src/test/java/com/shortthirdman/primekit/essentials/common/util/CompletableFutureUtilsTest.java b/src/test/java/com/shortthirdman/primekit/essentials/common/util/CompletableFutureUtilsTest.java new file mode 100644 index 0000000..c92652a --- /dev/null +++ b/src/test/java/com/shortthirdman/primekit/essentials/common/util/CompletableFutureUtilsTest.java @@ -0,0 +1,63 @@ +package com.shortthirdman.primekit.essentials.common.util; + +import org.junit.jupiter.api.Test; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import static org.junit.jupiter.api.Assertions.*; + +class CompletableFutureUtilsTest { + + @Test + void completesNormallyBeforeTimeout_cancelsTimeoutTask() { + CompletableFuture f = new CompletableFuture<>(); + CompletableFutureUtils.orTimeout(f, 200, TimeUnit.MILLISECONDS); + + // Complete before 200ms + f.complete("ok"); + + assertTrue(f.isDone()); + assertFalse(f.isCompletedExceptionally()); + assertEquals("ok", f.join()); + + // Sleep past the timeout to ensure the scheduled timeout would have fired if not cancelled + try { Thread.sleep(300); } catch (InterruptedException ignored) {} + // If the timeout wasn't cancelled, the future would be completed exceptionally already, which is not the case. + assertFalse(f.isCompletedExceptionally()); + } + + @Test + void timesOutWhenNotCompletedInTime_completesExceptionallyWithTimeoutException() { + CompletableFuture f = new CompletableFuture<>(); + CompletableFutureUtils.orTimeout(f, 50, TimeUnit.MILLISECONDS); + + // Do not complete the future; wait to let timeout trigger + try { Thread.sleep(120); } catch (InterruptedException ignored) {} + + assertTrue(f.isCompletedExceptionally()); + CompletionException ex = assertThrows(CompletionException.class, f::join); + assertInstanceOf(TimeoutException.class, ex.getCause()); + } + + @Test + void handlesNullArgumentsAndAlreadyCompletedFuture() { + // Null unit + CompletableFuture f1 = new CompletableFuture<>(); + assertThrows(NullPointerException.class, () -> CompletableFutureUtils.orTimeout(f1, 10, null)); + + // Null future + assertThrows(NullPointerException.class, () -> CompletableFutureUtils.orTimeout(null, 10, TimeUnit.MILLISECONDS)); + + // Already completed future should be returned as is and not be modified + CompletableFuture done = CompletableFuture.completedFuture(42); + CompletableFuture returned = CompletableFutureUtils.orTimeout(done, 10, TimeUnit.MILLISECONDS); + assertSame(done, returned); + assertEquals(42, returned.join()); + // Sleep beyond timeout to confirm nothing changes + try { Thread.sleep(50); } catch (InterruptedException ignored) {} + assertFalse(returned.isCompletedExceptionally()); + } +} \ No newline at end of file