diff --git a/.github/workflows/build-docker-mariadb.yml b/.github/workflows/build-docker-mariadb.yml index dfcbb52f2..0882613f8 100644 --- a/.github/workflows/build-docker-mariadb.yml +++ b/.github/workflows/build-docker-mariadb.yml @@ -16,17 +16,19 @@ jobs: with: fetch-depth: 0 - name: Set up JDK 17 - uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 # v3 + uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v4 with: java-version: '17' distribution: 'zulu' cache: gradle - name: Build the image - run: ./gradlew :fineract-provider:clean :fineract-provider:jibDockerBuild -x test + run: ./gradlew --no-daemon --console=plain :fineract-provider:clean :fineract-provider:build :fineract-provider:jibDockerBuild -x test -x cucumber - name: Start the stack - run: docker-compose up -d + run: docker compose up -d - name: Wait for stack to come up - run: sleep 300 + run: sleep 500 + - name: Check the stack + run: docker ps - name: Check health run: curl -f -k --retry 10 --retry-connrefused --connect-timeout 30 --retry-delay 30 https://localhost:8443/fineract-provider/actuator/health - name: Check info diff --git a/.github/workflows/build-docker-postgresql.yml b/.github/workflows/build-docker-postgresql.yml index ab9279081..53bb8d30d 100644 --- a/.github/workflows/build-docker-postgresql.yml +++ b/.github/workflows/build-docker-postgresql.yml @@ -16,17 +16,19 @@ jobs: with: fetch-depth: 0 - name: Set up JDK 17 - uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 # v3 + uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v4 with: java-version: '17' distribution: 'zulu' cache: gradle - name: Build the image - run: ./gradlew --no-daemon --console=plain :fineract-provider:clean :fineract-provider:jibDockerBuild -x test + run: ./gradlew --no-daemon --console=plain :fineract-provider:clean :fineract-provider:build :fineract-provider:jibDockerBuild -x test -x cucumber - name: Start the Standalone Stack - run: docker-compose -f docker-compose-postgresql.yml up -d + run: docker compose -f docker-compose-postgresql.yml up -d - name: Wait for stack to come up - run: sleep 300 + run: sleep 500 + - name: Check the stack + run: docker ps - name: Check health run: curl -f -k --retry 10 --retry-connrefused --connect-timeout 30 --retry-delay 30 https://localhost:8443/fineract-provider/actuator/health - name: Check info diff --git a/.github/workflows/build-documentation.yml b/.github/workflows/build-documentation.yml index 83982fafe..eae03a170 100644 --- a/.github/workflows/build-documentation.yml +++ b/.github/workflows/build-documentation.yml @@ -15,12 +15,12 @@ jobs: with: fetch-depth: 0 - name: Set up JDK 17 - uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 # v3 + uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v4 with: java-version: '17' distribution: 'zulu' cache: gradle - - uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4 + - uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4 with: node-version: 16 - name: Congfigure vega-cli diff --git a/.github/workflows/build-mariadb.yml b/.github/workflows/build-mariadb.yml index 0b76cb7ee..691403b37 100644 --- a/.github/workflows/build-mariadb.yml +++ b/.github/workflows/build-mariadb.yml @@ -10,7 +10,7 @@ jobs: services: mariad: - image: mariadb:11.1 + image: mariadb:11.2 ports: - 3306:3306 env: @@ -18,7 +18,7 @@ jobs: options: --health-cmd="healthcheck.sh --su-mysql --connect --innodb_initialized" --health-interval=5s --health-timeout=2s --health-retries=3 mock-oauth2-server: - image: ghcr.io/navikt/mock-oauth2-server:2.0.1 + image: ghcr.io/navikt/mock-oauth2-server:2.1.0 ports: - 9000:9000 env: @@ -34,12 +34,12 @@ jobs: with: fetch-depth: 0 - name: Set up JDK 17 - uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 # v3 + uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v4 with: java-version: '17' distribution: 'zulu' cache: gradle - - uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4 + - uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4 with: node-version: 16 - name: Congfigure vega-cli @@ -88,17 +88,18 @@ jobs: - name: Archive test results if: always() - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # tag=v3 + uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # tag=v3 with: name: test-results path: | + build/reports/ integration-tests/build/reports/ twofactor-tests/build/reports/ oauth2-tests/build/reports/ - name: Archive server logs if: always() - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # tag=v3 + uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # tag=v3 with: name: server-logs path: | diff --git a/.github/workflows/build-mysql.yml b/.github/workflows/build-mysql.yml index 09c507983..683d3e00e 100644 --- a/.github/workflows/build-mysql.yml +++ b/.github/workflows/build-mysql.yml @@ -18,7 +18,7 @@ jobs: options: --health-cmd="mysqladmin ping" --health-interval=5s --health-timeout=2s --health-retries=3 mock-oauth2-server: - image: ghcr.io/navikt/mock-oauth2-server:2.0.1 + image: ghcr.io/navikt/mock-oauth2-server:2.1.0 ports: - 9000:9000 env: @@ -34,12 +34,12 @@ jobs: with: fetch-depth: 0 - name: Set up JDK 17 - uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 # v3 + uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v4 with: java-version: '17' distribution: 'zulu' cache: gradle - - uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4 + - uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4 with: node-version: 16 - name: Congfigure vega-cli @@ -88,17 +88,18 @@ jobs: - name: Archive test results if: always() - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # tag=v3 + uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # tag=v3 with: name: test-results path: | + build/reports/ integration-tests/build/reports/ twofactor-tests/build/reports/ oauth2-tests/build/reports/ - name: Archive server logs if: always() - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # tag=v3 + uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # tag=v3 with: name: server-logs path: | diff --git a/.github/workflows/build-postgresql.yml b/.github/workflows/build-postgresql.yml index bcf577d09..f657d9a5f 100644 --- a/.github/workflows/build-postgresql.yml +++ b/.github/workflows/build-postgresql.yml @@ -19,7 +19,7 @@ jobs: options: --health-cmd="pg_isready -q -d postgres -U root" --health-interval=5s --health-timeout=2s --health-retries=3 mock-oauth2-server: - image: ghcr.io/navikt/mock-oauth2-server:2.0.1 + image: ghcr.io/navikt/mock-oauth2-server:2.1.0 ports: - 9000:9000 env: @@ -35,12 +35,12 @@ jobs: with: fetch-depth: 0 - name: Set up JDK 17 - uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 # v3 + uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v4 with: java-version: '17' distribution: 'zulu' cache: gradle - - uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4 + - uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4 with: node-version: 16 - name: Congfigure vega-cli @@ -89,17 +89,18 @@ jobs: - name: Archive test results if: always() - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # tag=v3 + uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # tag=v3 with: name: test-results path: | + build/reports/ integration-tests/build/reports/ twofactor-tests/build/reports/ oauth2-tests/build/reports/ - name: Archive server logs if: always() - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # tag=v3 + uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # tag=v3 with: name: server-logs path: | diff --git a/.github/workflows/smoke-activemq.yml b/.github/workflows/smoke-activemq.yml index 288040388..8f9455f0e 100644 --- a/.github/workflows/smoke-activemq.yml +++ b/.github/workflows/smoke-activemq.yml @@ -16,17 +16,19 @@ jobs: with: fetch-depth: 0 - name: Set up JDK 17 - uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 # v3 + uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v4 with: java-version: '17' distribution: 'zulu' cache: gradle - name: Build the image - run: ./gradlew --no-daemon --console=plain :fineract-provider:clean :fineract-provider:jibDockerBuild -x test + run: ./gradlew --no-daemon --console=plain :fineract-provider:clean :fineract-provider:build :fineract-provider:jibDockerBuild -x test -x cucumber - name: Start the ActiveMQ Stack - run: docker-compose -f docker-compose-postgresql-activemq.yml up --scale fineract-worker=1 -d + run: docker compose -f docker-compose-postgresql-activemq.yml up --scale fineract-worker=1 -d - name: Wait for stack to come up run: sleep 500 + - name: Check the stack + run: docker ps - name: Check health Manager run: curl -f -k --retry 10 --retry-connrefused --connect-timeout 30 --retry-delay 30 https://localhost:8443/fineract-provider/actuator/health - name: Check health Worker1 diff --git a/.github/workflows/smoke-kafka.yml b/.github/workflows/smoke-kafka.yml index ce8bc912d..e614cdc13 100644 --- a/.github/workflows/smoke-kafka.yml +++ b/.github/workflows/smoke-kafka.yml @@ -16,17 +16,19 @@ jobs: with: fetch-depth: 0 - name: Set up JDK 17 - uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 # v3 + uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v4 with: java-version: '17' distribution: 'zulu' cache: gradle - name: Build the image - run: ./gradlew --no-daemon --console=plain :fineract-provider:clean :fineract-provider:jibDockerBuild -x test + run: ./gradlew --no-daemon --console=plain :fineract-provider:clean :fineract-provider:build :fineract-provider:jibDockerBuild -x test -x cucumber - name: Start the Kafka Stack - run: docker-compose -f docker-compose-postgresql-kafka.yml up --scale fineract-worker=1 -d + run: docker compose -f docker-compose-postgresql-kafka.yml up --scale fineract-worker=1 -d - name: Wait for stack to come up run: sleep 500 + - name: Check the stack + run: docker ps - name: Check health Manager run: curl -f -k --retry 10 --retry-connrefused --connect-timeout 30 --retry-delay 30 https://localhost:8443/fineract-provider/actuator/health - name: Check health Worker1 diff --git a/.github/workflows/sonarqube.yml b/.github/workflows/sonarqube.yml index 94f7bb962..f240f1a68 100644 --- a/.github/workflows/sonarqube.yml +++ b/.github/workflows/sonarqube.yml @@ -24,7 +24,7 @@ jobs: with: fetch-depth: 0 - name: Set up JDK 17 - uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 # v3 + uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v4 with: java-version: '17' distribution: 'zulu' diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index ca79a7bdf..eb30dda52 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -15,7 +15,7 @@ jobs: pull-requests: write # for actions/stale to close stale PRs runs-on: ubuntu-latest steps: - - uses: actions/stale@1160a2240286f5da8ec72b1c0816ce2481aabf84 # v8 + - uses: actions/stale@28ca1036281a5e5922ead5184a1bbf96e5fc984e # v9 with: repo-token: ${{ secrets.GITHUB_TOKEN }} # stale-issue-message: 'Stale issue message' diff --git a/.profileconfig.json b/.profileconfig.json new file mode 100644 index 000000000..b2f42d90d --- /dev/null +++ b/.profileconfig.json @@ -0,0 +1,64 @@ +{ + "jfrConfig": { + "settings": "profile" + }, + "asyncProfilerConfig": { + "jfrsync": true, + "alloc": true, + "event": "wall", + "misc": "" + }, + "file": "$PROJECT_DIR/profile.jfr", + "conversionConfig": { + "nonProjectPackagePrefixes": [ + "java.", + "javax.", + "kotlin.", + "jdk.", + "com.google.", + "org.apache.", + "org.spring.", + "sun.", + "scala." + ], + "enableMarkers": true, + "initialVisibleThreads": 10, + "initialSelectedThreads": 10, + "includeGCThreads": false, + "includeInitialSystemProperty": false, + "includeInitialEnvironmentVariables": false, + "includeSystemProcesses": false, + "ignoredEvents": [ + "jdk.ActiveSetting", + "jdk.ActiveRecording", + "jdk.BooleanFlag", + "jdk.IntFlag", + "jdk.DoubleFlag", + "jdk.LongFlag", + "jdk.NativeLibrary", + "jdk.StringFlag", + "jdk.UnsignedIntFlag", + "jdk.UnsignedLongFlag", + "jdk.InitialSystemProperty", + "jdk.InitialEnvironmentVariable", + "jdk.SystemProcess", + "jdk.ModuleExport", + "jdk.ModuleRequire" + ], + "minRequiredItemsPerThread": 3 + }, + "additionalGradleTargets": [ + { + "targetPrefix": "quarkus", + "optionForVmArgs": "-Djvm.args", + "description": "Example quarkus config, adding profiling arguments via -Djvm.args option to the Gradle task run" + } + ], + "additionalMavenTargets": [ + { + "targetPrefix": "quarkus:", + "optionForVmArgs": "-Djvm.args", + "description": "Example quarkus config, adding profiling arguments via -Djvm.args option to the Maven goal run" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md index d715dac94..68991bcb8 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ Apache Fineract: A Platform for Microfinance ============ -[![Swagger Validation](https://validator.swagger.io/validator?url=https://demo.fineract.dev/fineract-provider/swagger-ui/fineract.yaml)](https://validator.swagger.io/validator/debug?url=https://demo.fineract.dev/fineract-provider/swagger-ui/fineract.yaml) [![build](https://github.com/apache/fineract/actions/workflows/build.yml/badge.svg)](https://github.com/apache/fineract/actions/workflows/build.yml) [![Docker Hub](https://img.shields.io/docker/pulls/apache/fineract.svg?logo=Docker)](https://hub.docker.com/r/apache/fineract) [![Docker Build](https://img.shields.io/docker/cloud/build/apache/fineract.svg?logo=Docker)](https://hub.docker.com/r/apache/fineract/builds) [![Technical Debt](https://sonarcloud.io/api/project_badges/measure?project=apache_fineract&metric=sqale_index)](https://sonarcloud.io/summary/new_code?id=apache_fineract) +[![Swagger Validation](https://validator.swagger.io/validator?url=https://sandbox.mifos.community/fineract-provider/swagger-ui/fineract.yaml)](https://validator.swagger.io/validator/debug?url=https://sandbox.mifos.community/fineract-provider/swagger-ui/fineract.yaml) [![build](https://github.com/apache/fineract/actions/workflows/build.yml/badge.svg)](https://github.com/apache/fineract/actions/workflows/build.yml) [![Docker Hub](https://img.shields.io/docker/pulls/apache/fineract.svg?logo=Docker)](https://hub.docker.com/r/apache/fineract) [![Docker Build](https://img.shields.io/docker/cloud/build/apache/fineract.svg?logo=Docker)](https://hub.docker.com/r/apache/fineract/builds) [![Technical Debt](https://sonarcloud.io/api/project_badges/measure?project=apache_fineract&metric=sqale_index)](https://sonarcloud.io/summary/new_code?id=apache_fineract) @@ -22,15 +22,15 @@ If you are interested in contributing to this project, but perhaps don't quite k REQUIREMENTS ============ * `Java >= 17` (Azul Zulu JVM is tested by our CI on GitHub Actions) -* MariaDB `10.9` +* MariaDB `11.2` You can run the required version of the database server in a container, instead of having to install it, like this: - docker run --name mariadb-10.9 -p 3306:3306 -e MARIADB_ROOT_PASSWORD=mysql -d mariadb:10.9 + docker run --name mariadb-11.2 -p 3306:3306 -e MARIADB_ROOT_PASSWORD=mysql -d mariadb:11.2 and stop and destroy it like this: - docker rm -f mariadb-10.9 + docker rm -f mariadb-11.2
Beware that this database container database keeps its state inside the container and not on the host filesystem. It is lost when you destroy (rm) this container. This is typically fine for development. See [Caveats: Where to Store Data on the database container documentation](https://hub.docker.com/_/mariadb) re. how to make it persistent instead of ephemeral.
@@ -75,7 +75,7 @@ Run the following commands: ============ 1. Clone the repository or download and extract the archive file to your local directory. 2. Run `./gradlew clean bootJar` to build a modern cloud native fully self contained JAR file which will be created at `fineract-provider/build/libs` directory. -3. As we are not allowed to include a JDBC driver in the built JAR, download a JDBC driver of your choice. For example: `wget https://downloads.mariadb.com/Connectors/java/connector-java-2.7.5/mariadb-java-client-2.7.5.jar` +3. As we are not allowed to include a JDBC driver in the built JAR, download a JDBC driver of your choice. For example: `wget https://downloads.mariadb.com/Connectors/java/connector-java-3.3.2/mariadb-java-client-3.3.2.jar` 4. Start the jar and pass the directory where you have downloaded the JDBC driver as loader.path, for example: `java -Dloader.path=. -jar fineract-provider/build/libs/fineract-provider.jar` (does not require external Tomcat) NOTE: we cannot upgrade to version 3.0.x of the MariaDB driver just yet; have to wait until 3.0.4 is out for a bug fix. @@ -207,13 +207,16 @@ _(Note that in previous versions, the `mysqlserver` environment variable used at `docker run` time did something similar; this has changed in [FINERACT-773](https://issues.apache.org/jira/browse/FINERACT-773)), and the `mysqlserver` environment variable is now no longer supported.)_ -If you need the Java Flight Recorder image then copy the file from the running fineract-development container: +The logfiles and the Java Flight Recorder output are available in `PROJECT_ROOT/build/fineract/logs`. If you use IntelliJ then you can double-click on the `.jfr` file and open it with the IDE. You can also download Azul Mission Control from here https://www.azul.com/products/components/azul-mission-control/ to analyze the Java Flight Recorder file. + +NOTE: If you have issues with the file permissions and Docker Compose then you might need to change the variable values for `FINERACT_USER` and `FINERACT_GROUP` in `PROJECT_ROOT/config/docker/env/fineract-common.env`. You can find out what values you need to put there with the following commands: ``` -docker container cp fineract-development:/tmp/fineract.jfr /tmp +id -u ${USER} +id -u ${GROUP} ``` -NOTE: Download Azul Mission Control from here https://www.azul.com/products/components/azul-mission-control/ to analyze the Java Flight Recorder file. +Please make sure that you are not checking in your changed values. The defaults should normally work for most people. Connection pool configuration ============================= @@ -399,9 +402,9 @@ complies with the [Apache Software Foundation third-party license policy](https:

APACHE FINERACT PLATFORM API ============ -The API for Fineract is documented in [apiLive.htm](fineract-provider/src/main/resources/static/api-docs/apiLive.htm), and the [apiLive.htm can be viewed on Fineract.dev](https://fineract.apache.org/legacy-docs/apiLive.htm "API Documentation"). If you have your own Fineract instance running, you can find this documentation under [/fineract-provider/api-docs/apiLive.htm](https://localhost:8443/fineract-provider/api-docs/apiLive.htm). +The API for Fineract is documented in [apiLive.htm](fineract-provider/src/main/resources/static/legacy-docs/apiLive.htm), and the [apiLive.htm can be viewed on fineract.apache.org](https://fineract.apache.org/docs/legacy/ "API Documentation"). If you have your own Fineract instance running, you can find this documentation under [/fineract-provider/legacy-docs/apiLive.htm](https://localhost:8443/fineract-provider/legacy-docs/apiLive.htm). -The Swagger documentation (work in progress; see [FINERACT-733](https://issues.apache.org/jira/browse/FINERACT-733)) can be accessed under [/fineract-provider/swagger-ui/index.html](https://localhost:8443/fineract-provider/swagger-ui/index.html) and [live Swagger UI here on Fineract.dev](https://demo.fineract.dev/fineract-provider/swagger-ui/index.html). +The Swagger documentation (work in progress; see [FINERACT-733](https://issues.apache.org/jira/browse/FINERACT-733)) can be accessed under [/fineract-provider/swagger-ui/index.html](https://localhost:8443/fineract-provider/swagger-ui/index.html) and [live Swagger UI here on Fineract.dev](https://sandbox.mifos.community/fineract-provider/swagger-ui/index.html). Apache Fineract supports client code generation using [Swagger Codegen](https://github.com/swagger-api/swagger-codegen) based on the [OpenAPI Specification](https://swagger.io/specification/). For more instructions on how to generate the client code, check [docs/developers/swagger/client.md](docs/developers/swagger/client.md). @@ -418,7 +421,7 @@ Apache Fineract supports client code generation using [Swagger Codegen](https://
ONLINE DEMOS ============ -* [fineract.dev](https://www.fineract.dev) always runs the latest version of this code +* [sandbox.mifos.community](https://sandbox.mifos.community) always runs the latest version of this code * [demo.mifos.io](https://demo.mifos.io) A demo account is provided for users to experience the functionality of the Community App. Users can use "mifos" for USERNAME and "password" for PASSWORD (without quotation marks). * [Swagger-UI Demo video](https://www.youtube.com/watch?v=FlVd-0YAo6c) This is a demo video for Swagger-UI documentation, more information [here](https://github.com/apache/fineract#swagger-ui-documentation). @@ -443,7 +446,7 @@ Apache Fineract / Mifos X Demo (November 2016) - GORVENANCE AND POLICIES ======================= diff --git a/build.gradle b/build.gradle index 9b1a17996..3ac3d7449 100644 --- a/build.gradle +++ b/build.gradle @@ -1,4 +1,4 @@ -/** + /** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information @@ -61,7 +61,7 @@ buildscript { classpath 'jakarta.ws.rs:jakarta.ws.rs-api:3.1.0' classpath 'com.google.cloud.tools:jib-layer-filter-extension-gradle:0.3.0' classpath 'org.apache.commons:commons-lang3:3.14.0' - classpath 'io.swagger.core.v3:swagger-jaxrs2-jakarta:2.2.11' + classpath 'io.swagger.core.v3:swagger-jaxrs2-jakarta:2.2.19' classpath 'jakarta.servlet:jakarta.servlet-api:6.0.0' } } @@ -70,14 +70,14 @@ plugins { id 'me.qoomon.git-versioning' version '6.4.3' id "org.barfuin.gradle.taskinfo" version "2.1.0" id 'com.adarshr.test-logger' version '4.0.0' - id 'com.diffplug.spotless' version '6.22.0' apply false + id 'com.diffplug.spotless' version '6.23.3' apply false id 'org.nosphere.apache.rat' version '0.8.1' apply false id 'com.github.hierynomus.license' version '0.16.1' apply false id 'com.github.jk1.dependency-license-report' version '2.5' apply false id 'org.zeroturnaround.gradle.jrebel' version '1.2.0' apply false - id 'org.springframework.boot' version '3.1.5' apply false + id 'org.springframework.boot' version '3.1.7' apply false id 'net.ltgt.errorprone' version '3.1.0' apply false - id 'io.swagger.core.v3.swagger-gradle-plugin' version '2.2.11' apply false + id 'io.swagger.core.v3.swagger-gradle-plugin' version '2.2.19' apply false id 'com.gorylenko.gradle-git-properties' version '2.4.1' apply false id 'org.asciidoctor.jvm.convert' version '3.3.2' apply false id 'org.asciidoctor.jvm.pdf' version '3.3.2' apply false @@ -88,9 +88,11 @@ plugins { id 'com.google.cloud.tools.jib' version '3.4.0' apply false id 'org.sonarqube' version '4.4.1.3373' id 'com.github.andygoossens.modernizer' version '1.9.0' apply false - id 'com.github.spotbugs' version '5.0.14' apply false + // TODO: upgrade to 6.0.4 + id 'com.github.spotbugs' version '5.0.15' apply false id 'se.thinkcode.cucumber-runner' version '0.0.11' apply false id "com.github.davidmc24.gradle.plugin.avro-base" version "1.9.1" apply false + id 'org.openapi.generator' version '7.2.0' apply false } apply from: "${rootDir}/buildSrc/src/main/groovy/org.apache.fineract.release.gradle" @@ -119,7 +121,7 @@ gitVersioning.apply { } } -ext['groovy.version'] = '4.0.6' +ext['groovy.version'] = '4.0.17' ext['swaggerFile'] = "$rootDir/fineract-provider/build/classes/java/main/static/fineract.json".toString() allprojects { @@ -143,7 +145,7 @@ allprojects { spotless { format 'misc', { target '**/*.md', '**/*.properties', '**/.gitignore', '**/.openapi-generator-ignore', '**/*.yml', '**/*.xml', '**/**.json', '**/*.sql' - targetExclude '**/build/**', '**/bin/**', '**/.settings/**', '**/.idea/**', '**/.gradle/**', '**/gradlew.bat', '**/licenses/**', '**/banner.txt', '.vscode/**' + targetExclude '**/build/**', '**/bin/**', '**/.settings/**', '**/.idea/**', '**/.gradle/**', '**/gradlew.bat', '**/licenses/**', '**/banner.txt', '.vscode/**', '.profileconfig.json' indentWithSpaces(4) endWithNewline() trimTrailingWhitespace() @@ -321,6 +323,15 @@ configure(project.fineractJavaProjects) { sourceSets.main.output.resourcesDir = sourceSets.main.java.classesDirectory sourceSets.test.output.resourcesDir = sourceSets.test.java.classesDirectory + configurations.named('spotbugs').configure { + resolutionStrategy.eachDependency { + if (it.requested.group == 'org.ow2.asm') { + it.useVersion '9.5' + it.because "Asm 9.5 is required for JDK 21 support" + } + } + } + configurations { implementation.setCanBeResolved(true) api.setCanBeResolved(true) @@ -423,7 +434,7 @@ configure(project.fineractJavaProjects) { // Configuration for the Checkstyle plugin // https://docs.gradle.org/current/userguide/checkstyle_plugin.html dependencies { - checkstyle 'com.puppycrawl.tools:checkstyle:10.12.5' + checkstyle 'com.puppycrawl.tools:checkstyle:10.12.7' checkstyle 'com.github.sevntu-checkstyle:sevntu-checks:1.44.1' } @@ -445,7 +456,7 @@ configure(project.fineractJavaProjects) { // Configuration for the errorprone plugin // https://github.com/tbroyer/gradle-errorprone-plugin dependencies { - errorprone "com.google.errorprone:error_prone_core:2.23.0" + errorprone "com.google.errorprone:error_prone_core:2.24.0" } tasks.withType(JavaCompile) { @@ -600,7 +611,8 @@ configure(project.fineractJavaProjects) { // To generate an HTML report instead of XML spotbugs { - reportLevel = 'high' + // reportLevel = 'high' + // reportLevel = com.github.spotbugs.snom.Confidence.DEFAULT showProgress = false excludeFilter = file("$rootDir/config/spotbugs/exclude.xml") } diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle index 4f609bbca..6f413c4e8 100644 --- a/buildSrc/build.gradle +++ b/buildSrc/build.gradle @@ -58,4 +58,5 @@ dependencies { implementation 'com.squareup.retrofit2:retrofit' implementation 'com.squareup.retrofit2:converter-jackson' implementation 'com.fasterxml.jackson.core:jackson-databind' + implementation 'com.squareup.okhttp3:okhttp' } diff --git a/buildSrc/src/main/groovy/org.apache.fineract.dependencies.gradle b/buildSrc/src/main/groovy/org.apache.fineract.dependencies.gradle index 29364efa8..d3f7ab317 100644 --- a/buildSrc/src/main/groovy/org.apache.fineract.dependencies.gradle +++ b/buildSrc/src/main/groovy/org.apache.fineract.dependencies.gradle @@ -22,18 +22,21 @@ apply plugin: 'io.spring.dependency-management' // https://github.com/spring-gradle-plugins/dependency-management-plugin dependencyManagement { imports { - mavenBom 'io.micrometer:micrometer-bom:1.12.0' - mavenBom 'org.springframework:spring-framework-bom:6.1.0' - mavenBom 'org.springframework.boot:spring-boot-dependencies:3.1.5' - mavenBom 'io.awspring.cloud:spring-cloud-aws-dependencies:3.0.3' - mavenBom 'io.opentelemetry:opentelemetry-bom:1.32.0' - mavenBom 'org.jetbrains.kotlin:kotlin-bom:1.9.20' + mavenBom 'com.squareup.okhttp3:okhttp-bom:4.12.0' + mavenBom 'org.slf4j:slf4j-bom:2.0.10' + mavenBom 'io.micrometer:micrometer-bom:1.12.1' + mavenBom 'org.springframework:spring-framework-bom:6.1.2' + mavenBom 'org.springframework.boot:spring-boot-dependencies:3.1.7' + mavenBom 'io.awspring.cloud:spring-cloud-aws-dependencies:3.0.4' + mavenBom 'io.opentelemetry:opentelemetry-bom:1.33.0' + mavenBom 'org.jetbrains.kotlin:kotlin-bom:1.9.22' mavenBom 'org.junit:junit-bom:5.10.1' - mavenBom 'com.fasterxml.jackson:jackson-bom:2.16.0' - mavenBom 'io.cucumber:cucumber-bom:7.14.0' - mavenBom 'io.netty:netty-bom:4.1.101.Final' - mavenBom 'org.mockito:mockito-bom:5.7.0' - mavenBom 'software.amazon.awssdk:bom:2.21.28' + mavenBom 'com.fasterxml.jackson:jackson-bom:2.16.1' + mavenBom 'io.cucumber:cucumber-bom:7.15.0' + mavenBom 'io.netty:netty-bom:4.1.104.Final' + mavenBom 'org.mockito:mockito-bom:5.8.0' + mavenBom 'software.amazon.awssdk:bom:2.22.9' + mavenBom 'io.github.resilience4j:resilience4j-bom:2.2.0' } dependencies { @@ -41,37 +44,31 @@ dependencyManagement { // We do not use :+ to get the latest available version available on Maven Central, as that could suddenly break things. // We use the Renovate Bot to automatically propose Pull Requests (PRs) when upgrades for all of these versions are available. - dependency 'org.slf4j:slf4j-api:2.0.9' - dependency 'org.slf4j:slf4j-simple:2.0.9' - dependency 'org.slf4j:jcl-over-slf4j:2.0.9' - dependency 'org.slf4j:jul-to-slf4j:2.0.9' - dependency 'org.slf4j:log4j-over-slf4j:2.0.9' - dependency 'ch.qos.logback:logback-core:1.4.11' - dependency 'ch.qos.logback:logback-classic:1.4.11' + dependency 'ch.qos.logback:logback-core:1.4.14' + dependency 'ch.qos.logback:logback-classic:1.4.14' dependency 'ch.qos.logback.contrib:logback-json-classic:0.1.5' dependency 'ch.qos.logback.contrib:logback-jackson:0.1.5' - dependency 'org.codehaus.janino:janino:3.1.10' + dependency 'org.codehaus.janino:janino:3.1.11' dependency 'org.eclipse.persistence:org.eclipse.persistence.jpa:4.0.0' dependency 'com.google.guava:guava:32.0.0-jre' dependency 'com.google.code.gson:gson:2.10.1' - dependency 'com.google.truth:truth:1.1.5' - dependency 'com.google.truth.extensions:truth-java8-extension:1.1.5' - dependency 'com.google.googlejavaformat:google-java-format:1.18.1' - dependency ('org.apache.commons:commons-email:1.5') { + dependency 'com.google.truth:truth:1.2.0' + dependency 'com.google.truth.extensions:truth-java8-extension:1.2.0' + dependency 'com.google.googlejavaformat:google-java-format:1.19.1' + dependency ('org.apache.commons:commons-email:1.6.0') { exclude 'com.sun.mail:javax.mail' exclude 'javax.activation:activation' } - dependency 'commons-io:commons-io:2.15.0' - dependency 'com.github.librepdf:openpdf:1.3.33' + dependency 'commons-io:commons-io:2.15.1' + dependency 'com.github.librepdf:openpdf:1.3.35' dependency ('org.mnode.ical4j:ical4j:3.2.14') { exclude 'com.sun.mail:javax.mail' exclude 'org.codehaus.groovy:groovy' } dependency 'org.apache.commons:commons-csv:1.10.0' dependency 'org.quartz-scheduler:quartz:2.3.2' - dependency 'software.amazon.awssdk:bom:2.21.28' dependency 'org.ehcache:ehcache:3.10.8' dependency 'com.github.spullara.mustache.java:compiler:0.9.11' dependency 'com.jayway.jsonpath:json-path:2.8.0' @@ -119,13 +116,14 @@ dependencyManagement { dependency 'jakarta.management.j2ee:jakarta.management.j2ee-api:1.1.4' dependency 'jakarta.jms:jakarta.jms-api:3.1.0' dependency 'jakarta.ws.rs:jakarta.ws.rs-api:3.1.0' - dependency 'org.glassfish.jersey.media:jersey-media-multipart:3.1.3' + dependency 'org.glassfish.jersey.media:jersey-media-multipart:3.1.5' dependency 'org.glassfish.jaxb:jaxb-runtime:2.3.6' // Swagger needs exactly this version dependency 'org.apache.bval:org.apache.bval.bundle:3.0.0' dependency 'joda-time:joda-time:2.12.5' dependency 'io.github.classgraph:classgraph:4.8.165' dependency 'org.awaitility:awaitility:4.2.0' + // TODO: upgrade to 4.8.3 dependency 'com.github.spotbugs:spotbugs-annotations:4.7.3' dependency 'javax.cache:cache-api:1.1.1' dependency 'org.mock-server:mockserver-junit-jupiter:5.15.0' @@ -148,16 +146,10 @@ dependencyManagement { dependency "com.squareup.retrofit2:converter-scalars:2.9.0" dependency "com.squareup.retrofit2:converter-gson:2.9.0" dependency "com.squareup.retrofit2:converter-protobuf:2.9.0" + dependency 'io.reactivex.rxjava2:rxjava:2.2.21' dependency "org.apache.oltu.oauth2:org.apache.oltu.oauth2.common:1.0.1" dependency "org.apache.oltu.oauth2:org.apache.oltu.oauth2.client:1.0.1" dependency "org.apache.oltu.oauth2:org.apache.oltu.oauth2.httpclient4:1.0.1" - dependency "com.squareup.okhttp3:okhttp:4.12.0" - dependency "com.squareup.okhttp3:okcurl:4.12.0" - dependency "com.squareup.okhttp3:logging-interceptor:4.12.0" - dependency "com.squareup.okhttp3:okhttp-apache:4.9.3" - dependency "com.squareup.okhttp3:okhttp-android-support:4.9.3" - dependency "com.squareup.okhttp3:okhttp-urlconnection:4.12.0" - dependency "com.squareup.okhttp3:okhttp-sse:4.12.0" dependency "io.gsonfire:gson-fire:1.9.0" dependency "com.google.code.findbugs:jsr305:3.0.2" dependency "commons-codec:commons-codec:1.16.0" @@ -168,44 +160,45 @@ dependencyManagement { dependency 'org.bouncycastle:bcprov-jdk15on:1.70' dependency 'org.bouncycastle:bcpg-jdk15on:1.70' - dependency 'org.eclipse.jgit:org.eclipse.jgit:6.7.0.202309050840-r' - dependency 'org.eclipse.jgit:org.eclipse.jgit.ssh.apache:6.7.0.202309050840-r' + dependency 'org.eclipse.jgit:org.eclipse.jgit:6.8.0.202311291450-r' + dependency 'org.eclipse.jgit:org.eclipse.jgit.ssh.apache:6.8.0.202311291450-r' dependency 'org.tmatesoft.svnkit:svnkit:1.10.11' dependency 'com.vdurmont:semver4j:3.1.0' dependency 'org.beryx:text-io:3.4.1' - dependency ('org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0') { + dependency ('org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0') { exclude 'io.swagger.core.v3:swagger-core' } - dependency 'com.google.cloud.sql:mysql-socket-factory-connector-j-8:1.15.0' + dependency 'com.google.cloud.sql:mysql-socket-factory-connector-j-8:1.15.1' - dependency ('org.apache.activemq:activemq-client:6.0.0') { + dependency ('org.apache.activemq:activemq-client:6.0.1') { exclude 'javax.annotation:javax.annotation-api' } - dependency 'io.swagger.core.v3:swagger-annotations-jakarta:2.2.11' - dependency ('io.swagger.core.v3:swagger-jaxrs2-jakarta:2.2.11') { + dependency 'io.swagger.core.v3:swagger-annotations-jakarta:2.2.19' + dependency ('io.swagger.core.v3:swagger-jaxrs2-jakarta:2.2.19') { exclude 'jakarta.activation:jakarta.activation-api' } - dependency ('io.swagger.core.v3:swagger-core-jakarta:2.2.11') { + dependency ('io.swagger.core.v3:swagger-core-jakarta:2.2.19') { exclude 'jakarta.activation:jakarta.activation-api' } - dependency "jakarta.annotation:jakarta.annotation-api:2.1.1" + dependency 'jakarta.annotation:jakarta.annotation-api:2.1.1' dependency 'jakarta.activation:jakarta.activation-api:2.1.2' dependency ('com.sun.mail:jakarta.mail:2.0.1') { // Spring needs this version exclude 'com.sun.activation:jakarta.activation' } - dependency ('jakarta.xml.bind:jakarta.xml.bind-api:4.0.0') { + dependency ('jakarta.xml.bind:jakarta.xml.bind-api:4.0.1') { exclude 'jakarta.activation:jakarta.activation-api' } - dependency ('org.liquibase:liquibase-core:4.23.0') { + dependency ('org.liquibase:liquibase-core:4.25.1') { exclude 'javax.xml.bind:jaxb-api' } + dependency 'org.liquibase.ext:liquibase-postgresql:4.25.1' dependency ('org.dom4j:dom4j:2.1.4') { exclude 'relaxngDatatype:relaxngDatatype' // already in com.sun.xml.bind:jaxb-osgi:2.3.0.1 @@ -214,38 +207,36 @@ dependencyManagement { exclude 'pull-parser:pull-parser' } - dependency 'org.owasp.esapi:esapi:2.5.2.0' + dependency 'org.owasp.esapi:esapi:2.5.3.1' dependency 'org.awaitility:awaitility:4.2.0' - dependencySet(group: 'org.apache.poi', version: '5.2.4') { + dependencySet(group: 'org.apache.poi', version: '5.2.5') { entry 'poi' entry 'poi-ooxml' entry 'poi-ooxml-schemas' } - dependencySet(group: 'io.rest-assured', version: '5.3.2') { + dependencySet(group: 'io.rest-assured', version: '5.4.0') { entry 'rest-assured' entry 'json-path' entry 'xml-path' } - dependency 'org.apache.groovy:groovy-xml:4.0.14' - dependency 'org.apache.groovy:groovy-json:4.0.15' + dependency 'org.apache.groovy:groovy-xml:4.0.17' + dependency 'org.apache.groovy:groovy-json:4.0.17' dependency 'org.mapstruct:mapstruct:1.5.5.Final' dependency 'org.mapstruct:mapstruct-processor:1.5.5.Final' dependency "org.apache.avro:avro:1.11.3" - dependency "io.github.resilience4j:resilience4j-spring-boot2:2.1.0" - - dependency ('org.mariadb.jdbc:mariadb-java-client:3.3.0') { + dependency ('org.mariadb.jdbc:mariadb-java-client:3.3.2') { exclude 'org.slf4j:jcl-over-slf4j' exclude 'org.slf4j:slf4j-api' } - dependency 'org.postgresql:postgresql:42.7.0' + dependency 'org.postgresql:postgresql:42.7.1' - dependency 'org.assertj:assertj-core:3.24.2' + dependency 'org.assertj:assertj-core:3.25.0' dependency 'org.apache.commons:commons-math3:3.6.1' diff --git a/config/docker/compose/activemq.yml b/config/docker/compose/activemq.yml index e60c40f93..80c6699f5 100644 --- a/config/docker/compose/activemq.yml +++ b/config/docker/compose/activemq.yml @@ -22,5 +22,5 @@ services: activemq: image: symptoma/activemq:5.18.3 ports: - - 6161:6161 - - 61616:61616 + - "6161:6161" + - "61616:61616" diff --git a/config/docker/compose/fineract-custom.yml b/config/docker/compose/fineract-custom.yml new file mode 100644 index 000000000..d46ef411b --- /dev/null +++ b/config/docker/compose/fineract-custom.yml @@ -0,0 +1,32 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +version: "3.8" + +services: + fineract: + # user: "${FINERACT_USER}:${FINERACT_GROUP}" + image: fineract-custom:latest + volumes: + - ${PWD}/config/docker/logback/logback-override.xml:/app/logback-override.xml + - ${PWD}/config/docker/aws/etc/credentials:/etc/aws/credentials:ro + - ${PWD}/build/fineract/logs:/var/logs/fineract:rw + healthcheck: + test: ["CMD", 'sh', '-c', 'echo -e "Checking for the availability of Fineract server deployment"; while ! nc -z "localhost" 8443; do sleep 1; printf "-"; done; echo -e " >> Fineract server has started";' ] + timeout: 1s + retries: 60 diff --git a/config/docker/compose/fineract.yml b/config/docker/compose/fineract.yml index e4a3be880..ae5323c41 100644 --- a/config/docker/compose/fineract.yml +++ b/config/docker/compose/fineract.yml @@ -20,12 +20,13 @@ version: "3.8" services: fineract: + # user: "${FINERACT_USER}:${FINERACT_GROUP}" image: fineract:latest volumes: - - ../aws/etc/credentials:/etc/aws/credentials + - ${PWD}/config/docker/logback/logback-override.xml:/app/logback-override.xml + - ${PWD}/config/docker/aws/etc/credentials:/etc/aws/credentials:ro + - ${PWD}/build/fineract/logs:/var/logs/fineract:rw healthcheck: - test: ["CMD", 'sh', '-c', 'echo -e "Checking for the availability of Fineract server deployment"; while ! nc -z "fineract-server" 8443; do sleep 1; printf "-"; done; echo -e " >> Fineract server has started";' ] - timeout: 10s - retries: 10 - env_file: - - ../env/fineract-common.env + test: ["CMD", 'sh', '-c', 'echo -e "Checking for the availability of Fineract server deployment"; while ! nc -z "localhost" 8443; do sleep 1; printf "-"; done; echo -e " >> Fineract server has started";' ] + timeout: 1s + retries: 60 diff --git a/config/docker/compose/mariadb.yml b/config/docker/compose/mariadb.yml index 75a5483bc..2c56ec155 100644 --- a/config/docker/compose/mariadb.yml +++ b/config/docker/compose/mariadb.yml @@ -13,22 +13,20 @@ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations -# under the License. -# - version: "3.8" services: mariadb: - image: mariadb:11.0 + container_name: mariadb + image: mariadb:11.2 volumes: - - ../mysql/conf.d/server_collation.cnf:/etc/mysql/conf.d/server_collation.cnf - - ../mysql/docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d:Z,ro + - ${PWD}/config/docker/mysql/conf.d/server_collation.cnf:/etc/mysql/conf.d/server_collation.cnf:ro + - ${PWD}/config/docker/mysql/docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d:Z,ro restart: always env_file: - - ../env/mysql.env + - ${PWD}/config/docker/env/mysql.env healthcheck: - test: ["CMD", "healthcheck.sh", "--su-mysql", "--connect", "--innodb_initialized"] + test: [ "CMD", "healthcheck.sh", "--su-mysql", "--connect", "--innodb_initialized" ] timeout: 10s retries: 10 ports: diff --git a/config/docker/compose/observability.yml b/config/docker/compose/observability.yml index dc1f6d41f..de59e1870 100644 --- a/config/docker/compose/observability.yml +++ b/config/docker/compose/observability.yml @@ -31,31 +31,35 @@ version: "3.8" services: loki: + container_name: loki image: grafana/loki:2.9.2 command: -config.file=/etc/loki/local-config.yaml ports: - "3100:3100" prometheus: + container_name: prometheus image: prom/prometheus:v2.47.2 command: '--config.file=/etc/prometheus/prometheus.yml' ports: - "9090:9090" volumes: - - ../prometheus/etc:/etc/prometheus + - ${PWD}/config/docker/prometheus/etc:/etc/prometheus logging: *default-logging grafana: + container_name: grafana image: grafana/grafana-oss:10.2.0 ports: - "3000:3000" volumes: - - ../grafana/datasources:/etc/grafana/provisioning/datasources - - ../grafana/etc/dashboards.yml:/etc/grafana/provisioning/dashboards/dashboards.yaml - - ../grafana/dashboards:/var/lib/grafana/dashboards + - ${PWD}/config/docker/grafana/datasources:/etc/grafana/provisioning/datasources + - ${PWD}/config/docker/grafana/etc/dashboards.yml:/etc/grafana/provisioning/dashboards/dashboards.yaml + - ${PWD}/config/docker/grafana/dashboards:/var/lib/grafana/dashboards logging: *default-logging tempo: + container_name: tempo image: grafana/tempo:2.2.4 # command: [ "--target=all", "--storage.trace.backend=local", "--storage.trace.local.path=/tmp/tempo", "--auth.enabled=false" ] command: [ "-config.file=/etc/tempo.yml" ] @@ -67,6 +71,6 @@ services: - "4318:4318" # otlp http - "9411:9411" # zipkin volumes: - - ../tempo/etc/tempo.yml:/etc/tempo.yml + - ${PWD}/config/docker/tempo/etc/tempo.yml:/etc/tempo.yml - /tmp/tempo:/tmp/tempo logging: *default-logging diff --git a/config/docker/compose/postgresql.yml b/config/docker/compose/postgresql.yml index 4c87ba90f..878c88264 100644 --- a/config/docker/compose/postgresql.yml +++ b/config/docker/compose/postgresql.yml @@ -20,12 +20,12 @@ version: "3.8" services: postgresql: - image: postgres:16.0 + image: postgres:16.1 volumes: - - ../postgresql/docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d/:Z,ro + - ${PWD}/config/docker/postgresql/docker-entrypoint-initdb.d/01-init.sh:/docker-entrypoint-initdb.d/01-init.sh:Z,ro restart: always env_file: - - ../env/postgresql.env + - ${PWD}/config/docker/env/postgresql.env healthcheck: test: [ "CMD", "pg_isready", "-q", "-d", "postgres", "-U", "root" ] timeout: 10s diff --git a/config/docker/env/debug.env b/config/docker/env/debug.env index fcddc452e..34023e558 100644 --- a/config/docker/env/debug.env +++ b/config/docker/env/debug.env @@ -18,4 +18,5 @@ # # see here for more details related to JFR: https://access.redhat.com/documentation/en-us/red_hat_build_of_openjdk/8/html/using_jdk_flight_recorder_with_red_hat_build_of_openjdk/configure-jfr-options -JAVA_TOOL_OPTIONS="-Xmx2G -Xms2G -XX:TieredStopAtLevel=1 -XX:+UseContainerSupport -XX:+UseStringDeduplication -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5000 -XX:+UnlockDiagnosticVMOptions -XX:+DebugNonSafepoints -XX:StartFlightRecording=delay=20s,duration=60s,disk=true,name=fineract,dumponexit=true,filename=/tmp/fineract.jfr,settings=profile -Xlog:jfr=info" +# JAVA_TOOL_OPTIONS="-Xmx2G -Xms2G -Dlogging.config=/app/logback-override.xml -XX:TieredStopAtLevel=1 -XX:+UseContainerSupport -XX:+UseStringDeduplication -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5000 -XX:+UnlockDiagnosticVMOptions -XX:+DebugNonSafepoints -XX:StartFlightRecording=delay=20s,duration=60s,disk=true,name=fineract,path-to-gc-roots=true,dumponexit=true,filename=/var/logs/fineract/fineract.jfr,settings=profile -Xlog:jfr=info" +JAVA_TOOL_OPTIONS="-Xmx2G -Xms2G -Dlogging.config=/app/logback-override.xml -XX:TieredStopAtLevel=1 -XX:+UseContainerSupport -XX:+UseStringDeduplication -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5000 -XX:+UnlockDiagnosticVMOptions -XX:+DebugNonSafepoints -Xlog:jfr=info" diff --git a/config/docker/env/fineract-common.env b/config/docker/env/fineract-common.env index cff62452c..fd1f0f228 100644 --- a/config/docker/env/fineract-common.env +++ b/config/docker/env/fineract-common.env @@ -18,6 +18,8 @@ # # ... following variables are optional; "application.properties" contains reasonable defaults (same as here) +FINERACT_USER=1000 +FINERACT_GROUP=1000 FINERACT_HIKARI_MINIMUM_IDLE=3 FINERACT_HIKARI_MAXIMUM_POOL_SIZE=10 FINERACT_HIKARI_IDLE_TIMEOUT=60000 @@ -25,6 +27,8 @@ FINERACT_HIKARI_CONNECTION_TIMEOUT=20000 FINERACT_HIKARI_TEST_QUERY=SELECT 1 FINERACT_HIKARI_AUTO_COMMIT=true FINERACT_SERVER_SSL_ENABLED=true +FINERACT_HIKARI_USERNAME=root +FINERACT_HIKARI_PASSWORD=skdcnwauicn2ucnaecasdsajdnizucawencascdca FINERACT_HIKARI_DS_PROPERTIES_CACHE_PREP_STMTS=true FINERACT_HIKARI_DS_PROPERTIES_PREP_STMT_CACHE_SIZE=250 FINERACT_HIKARI_DS_PROPERTIES_PREP_STMT_CACHE_SQL_LIMIT=2048 @@ -37,14 +41,19 @@ FINERACT_HIKARI_DS_PROPERTIES_ELIDE_SET_AUTO_COMMITS=true FINERACT_HIKARI_DS_PROPERTIES_MAINTAIN_TIME_STATS=false FINERACT_HIKARI_DS_PROPERTIES_LOG_SLOW_QUERIES=true FINERACT_HIKARI_DS_PROPERTIES_DUMP_QUERIES_IN_EXCEPTION=true +# NOTE: env vars prefixed "FINERACT_DEFAULT_TENANTDB_*" are used to create the default tenant database FINERACT_DEFAULT_TENANTDB_CONN_PARAMS= FINERACT_DEFAULT_TENANTDB_TIMEZONE=Asia/Kolkata FINERACT_DEFAULT_TENANTDB_IDENTIFIER=default FINERACT_DEFAULT_TENANTDB_NAME=fineract_default FINERACT_DEFAULT_TENANTDB_DESCRIPTION=Default Demo Tenant +FINERACT_DEFAULT_TENANTDB_HOSTNAME=db +FINERACT_DEFAULT_TENANTDB_PWD=skdcnwauicn2ucnaecasdsajdnizucawencascdca +FINERACT_DEFAULT_MASTER_PASSWORD=fineract FINERACT_MANAGEMENT_ENDPOINT_WEB_EXPOSURE_INCLUDE=health,info,prometheus FINERACT_MANAGEMENT_METRICS_TAGS_APPLICATION=fineract FINERACT_REMOTE_JOB_MESSAGE_HANDLER_SPRING_EVENTS_ENABLED=false +FINERACT_INSECURE_HTTP_CLIENT=true SPRING_PROFILES_ACTIVE=test,diagnostics OTEL_SERVICE_NAME=fineract JAVA_TOOL_OPTIONS="-Xmx1G -XX:TieredStopAtLevel=1 -XX:+UseContainerSupport -XX:+UseStringDeduplication" diff --git a/config/docker/env/fineract-mariadb.env b/config/docker/env/fineract-mariadb.env index 6a9bc7d54..af84f543d 100644 --- a/config/docker/env/fineract-mariadb.env +++ b/config/docker/env/fineract-mariadb.env @@ -20,10 +20,6 @@ # NOTE: env vars prefixed "FINERACT_HIKARI_*" are used to configure the database connection pool FINERACT_HIKARI_DRIVER_SOURCE_CLASS_NAME=org.mariadb.jdbc.Driver FINERACT_HIKARI_JDBC_URL=jdbc:mariadb://db:3306/fineract_tenants -FINERACT_HIKARI_USERNAME=root -FINERACT_HIKARI_PASSWORD=skdcnwauicn2ucnaecasdsajdnizucawencascdca # NOTE: env vars prefixed "FINERACT_DEFAULT_TENANTDB_*" are used to create the default tenant database -FINERACT_DEFAULT_TENANTDB_HOSTNAME=db FINERACT_DEFAULT_TENANTDB_PORT=3306 FINERACT_DEFAULT_TENANTDB_UID=root -FINERACT_DEFAULT_TENANTDB_PWD=skdcnwauicn2ucnaecasdsajdnizucawencascdca diff --git a/config/docker/env/fineract-postgresql.env b/config/docker/env/fineract-postgresql.env index 99c5355ae..1fb152da9 100644 --- a/config/docker/env/fineract-postgresql.env +++ b/config/docker/env/fineract-postgresql.env @@ -23,7 +23,5 @@ FINERACT_HIKARI_JDBC_URL=jdbc:postgresql://db:5432/fineract_tenants FINERACT_HIKARI_USERNAME=postgres FINERACT_HIKARI_PASSWORD=skdcnwauicn2ucnaecasdsajdnizucawencascdca # NOTE: env vars prefixed "FINERACT_DEFAULT_TENANTDB_*" are used to create the default tenant database -FINERACT_DEFAULT_TENANTDB_HOSTNAME=db FINERACT_DEFAULT_TENANTDB_PORT=5432 FINERACT_DEFAULT_TENANTDB_UID=postgres -FINERACT_DEFAULT_TENANTDB_PWD=skdcnwauicn2ucnaecasdsajdnizucawencascdca diff --git a/config/docker/env/fineract-worker.env b/config/docker/env/fineract-worker.env index 0245b5a13..e7ad8555c 100644 --- a/config/docker/env/fineract-worker.env +++ b/config/docker/env/fineract-worker.env @@ -21,3 +21,4 @@ FINERACT_NODE_ID=2 FINERACT_MODE_BATCH_MANAGER_ENABLED=false FINERACT_MODE_BATCH_WORKER_ENABLED=true OTEL_SERVICE_NAME=fineract-worker +FINERACT_LIQUIBASE_ENABLED=false \ No newline at end of file diff --git a/config/docker/logback/logback-override.xml b/config/docker/logback/logback-override.xml new file mode 100644 index 000000000..4c5871f76 --- /dev/null +++ b/config/docker/logback/logback-override.xml @@ -0,0 +1,61 @@ + + + + + + + false + + + + false + + %green(%d{yyyy-MM-dd HH:mm:ss.SSS}) [%thread] %highlight(%-5level) %cyan(%logger{36}) - %msg%n + + + + + /var/logs/fineract/fineract.log + true + true + + /var/logs/fineract/fineract.%d{yyyy-MM-dd}.log + 2 + 100MB + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + UTF-8 + + + + + + + + + + diff --git a/config/spotbugs/exclude.xml b/config/spotbugs/exclude.xml index b5c1ed495..251015bb6 100644 --- a/config/spotbugs/exclude.xml +++ b/config/spotbugs/exclude.xml @@ -26,4 +26,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/custom/docker/docker-compose.yml b/custom/docker/docker-compose.yml deleted file mode 100644 index ae5b69d00..000000000 --- a/custom/docker/docker-compose.yml +++ /dev/null @@ -1,87 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# - -# You can replace and test a more recent version of docker compose -version: '3.7' -services: - # Backend service - fineractmysql: - image: mariadb:11.1 - volumes: - - ../../fineract-db/server_collation.cnf:/etc/mysql/conf.d/server_collation.cnf - - ../../fineract-db/docker:/docker-entrypoint-initdb.d:Z,ro - restart: always - environment: - MYSQL_ROOT_PASSWORD: skdcnwauicn2ucnaecasdsajdnizucawencascdca - healthcheck: - test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost", "--password=skdcnwauicn2ucnaecasdsajdnizucawencascdca" ] - timeout: 10s - retries: 10 - ports: - - "3306:3306" - fineract-server: - image: fineract-custom:latest - volumes: - - ../../fineract-provider/build/data:/data - healthcheck: - test: ["CMD", 'sh', '-c', 'echo -e "Checking for the availability of Fineract server deployment"; while ! nc -z "fineract-server" 8443; do sleep 1; printf "-"; done; echo -e " >> Fineract server has started";' ] - timeout: 10s - retries: 10 - ports: - - 8443:8443 - depends_on: - fineractmysql: - condition: service_healthy - environment: - # NOTE: node aware scheduler - - FINERACT_NODE_ID=1 - # NOTE: env vars prefixed "FINERACT_HIKARI_*" are used to configure the database connection pool - - FINERACT_HIKARI_DRIVER_SOURCE_CLASS_NAME=org.mariadb.jdbc.Driver - - FINERACT_HIKARI_JDBC_URL=jdbc:mariadb://fineractmysql:3306/fineract_tenants - - FINERACT_HIKARI_USERNAME=root - - FINERACT_HIKARI_PASSWORD=skdcnwauicn2ucnaecasdsajdnizucawencascdca - # ... following variables are optional; "application.properties" contains reasonable defaults (same as here) - - FINERACT_HIKARI_MINIMUM_IDLE=3 - - FINERACT_HIKARI_MAXIMUM_POOL_SIZE=10 - - FINERACT_HIKARI_IDLE_TIMEOUT=60000 - - FINERACT_HIKARI_CONNECTION_TIMEOUT=20000 - - FINERACT_HIKARI_TEST_QUERY=SELECT 1 - - FINERACT_HIKARI_AUTO_COMMIT=true - - FINERACT_HIKARI_DS_PROPERTIES_CACHE_PREP_STMTS=true - - FINERACT_HIKARI_DS_PROPERTIES_PREP_STMT_CACHE_SIZE=250 - - FINERACT_HIKARI_DS_PROPERTIES_PREP_STMT_CACHE_SQL_LIMIT=2048 - - FINERACT_HIKARI_DS_PROPERTIES_USE_SERVER_PREP_STMTS=true - - FINERACT_HIKARI_DS_PROPERTIES_USE_LOCAL_SESSION_STATE=true - - FINERACT_HIKARI_DS_PROPERTIES_REWRITE_BATCHED_STATEMENTS=true - - FINERACT_HIKARI_DS_PROPERTIES_CACHE_RESULT_SET_METADATA=true - - FINERACT_HIKARI_DS_PROPERTIES_CACHE_SERVER_CONFIGURATION=true - - FINERACT_HIKARI_DS_PROPERTIES_ELIDE_SET_AUTO_COMMITS=true - - FINERACT_HIKARI_DS_PROPERTIES_MAINTAIN_TIME_STATS=false - - FINERACT_HIKARI_DS_PROPERTIES_LOG_SLOW_QUERIES=true - - FINERACT_HIKARI_DS_PROPERTIES_DUMP_QUERIES_IN_EXCEPTION=true - # NOTE: env vars prefixed "FINERACT_DEFAULT_TENANTDB_*" are used to create the default tenant database - - FINERACT_DEFAULT_TENANTDB_HOSTNAME=fineractmysql - - FINERACT_DEFAULT_TENANTDB_PORT=3306 - - FINERACT_DEFAULT_TENANTDB_UID=root - - FINERACT_DEFAULT_TENANTDB_PWD=skdcnwauicn2ucnaecasdsajdnizucawencascdca - - FINERACT_DEFAULT_TENANTDB_CONN_PARAMS= - - FINERACT_DEFAULT_TENANTDB_TIMEZONE=Asia/Kolkata - - FINERACT_DEFAULT_TENANTDB_IDENTIFIER=default - - FINERACT_DEFAULT_TENANTDB_NAME=fineract_default - - FINERACT_DEFAULT_TENANTDB_DESCRIPTION=Default Demo Tenant - - JAVA_TOOL_OPTIONS="-Xmx1G" diff --git a/docker-compose-custom.yml b/docker-compose-custom.yml new file mode 100644 index 000000000..ecb2d72ec --- /dev/null +++ b/docker-compose-custom.yml @@ -0,0 +1,39 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +# You can replace and test a more recent version of docker compose +version: "3.8" +services: + db: + extends: + file: ./config/docker/compose/mariadb.yml + service: mariadb + + fineract: + extends: + file: ./config/docker/compose/fineract-custom.yml + service: fineract + ports: + - "8443:8443" + depends_on: + db: + condition: service_healthy + env_file: + - ./config/docker/env/fineract.env + - ./config/docker/env/fineract-common.env + - ./config/docker/env/fineract-mariadb.env diff --git a/docker-compose-development.yml b/docker-compose-development.yml index f08937072..ddaf50c99 100644 --- a/docker-compose-development.yml +++ b/docker-compose-development.yml @@ -79,8 +79,9 @@ services: condition: service_started env_file: - ./config/docker/env/aws.env - - ./config/docker/env/fineract-mariadb.env - ./config/docker/env/fineract.env + - ./config/docker/env/fineract-common.env + - ./config/docker/env/fineract-mariadb.env - ./config/docker/env/tracing.env - ./config/docker/env/oltp.env - ./config/docker/env/prometheus.env diff --git a/docker-compose-postgresql-activemq.yml b/docker-compose-postgresql-activemq.yml index 2055a5426..7e5961f3e 100644 --- a/docker-compose-postgresql-activemq.yml +++ b/docker-compose-postgresql-activemq.yml @@ -39,8 +39,9 @@ services: db: condition: service_healthy env_file: - - ./config/docker/env/fineract-postgresql.env - ./config/docker/env/fineract-manager.env + - ./config/docker/env/fineract-common.env + - ./config/docker/env/fineract-postgresql.env - ./config/docker/env/activemq.env fineract-worker: @@ -53,9 +54,10 @@ services: ports: - "8444-8445:8443" depends_on: - db: + fineract-manager: condition: service_healthy env_file: - - ./config/docker/env/fineract-postgresql.env - ./config/docker/env/fineract-worker.env + - ./config/docker/env/fineract-common.env + - ./config/docker/env/fineract-postgresql.env - ./config/docker/env/activemq.env diff --git a/docker-compose-postgresql-kafka-msk.yml b/docker-compose-postgresql-kafka-msk.yml index 3e1cfa0af..8ca2cef0f 100644 --- a/docker-compose-postgresql-kafka-msk.yml +++ b/docker-compose-postgresql-kafka-msk.yml @@ -19,7 +19,6 @@ version: "3.8" services: - db: extends: file: ./config/docker/compose/postgresql.yml @@ -35,8 +34,10 @@ services: db: condition: service_healthy env_file: - - ./config/docker/env/aws.env - ./config/docker/env/fineract-manager.env + - ./config/docker/env/fineract-common.env + - ./config/docker/env/fineract-postgresql.env + - ./config/docker/env/aws.env - ./config/docker/env/kafka-client-msk.env fineract-worker: @@ -49,9 +50,11 @@ services: ports: - "8444-8445:8443" depends_on: - db: + fineract-manager: condition: service_healthy env_file: - - ./config/docker/env/aws.env - ./config/docker/env/fineract-worker.env + - ./config/docker/env/fineract-common.env + - ./config/docker/env/fineract-postgresql.env + - ./config/docker/env/aws.env - ./config/docker/env/kafka-client-msk.env diff --git a/docker-compose-postgresql-kafka.yml b/docker-compose-postgresql-kafka.yml index c0fbb895a..92e6cf2a0 100644 --- a/docker-compose-postgresql-kafka.yml +++ b/docker-compose-postgresql-kafka.yml @@ -17,12 +17,12 @@ # # You can replace and test a more recent version of docker compose -version: '3.7' +version: "3.7" services: kafka: - image: 'bitnami/kafka:3.5.1-debian-11-r7' + image: "bitnami/kafka:3.5.1-debian-11-r7" ports: - - '9092:9092' + - "9092:9092" env_file: - ./config/docker/env/kafka-server.env @@ -40,9 +40,12 @@ services: depends_on: db: condition: service_healthy + kafka: + condition: service_started env_file: - - ./config/docker/env/fineract-postgresql.env - ./config/docker/env/fineract-manager.env + - ./config/docker/env/fineract-common.env + - ./config/docker/env/fineract-postgresql.env - ./config/docker/env/kafka-client.env fineract-worker: @@ -55,9 +58,10 @@ services: ports: - "8444-8445:8443" depends_on: - db: + fineract-manager: condition: service_healthy env_file: - - ./config/docker/env/fineract-postgresql.env - ./config/docker/env/fineract-worker.env + - ./config/docker/env/fineract-common.env + - ./config/docker/env/fineract-postgresql.env - ./config/docker/env/kafka-client.env diff --git a/docker-compose-postgresql.yml b/docker-compose-postgresql.yml index e6a5690b6..181fb6f7c 100644 --- a/docker-compose-postgresql.yml +++ b/docker-compose-postgresql.yml @@ -35,5 +35,6 @@ services: db: condition: service_healthy env_file: - - ./config/docker/env/fineract-postgresql.env - ./config/docker/env/fineract.env + - ./config/docker/env/fineract-common.env + - ./config/docker/env/fineract-postgresql.env diff --git a/docker-compose.yml b/docker-compose.yml index 17417a627..d67579612 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -35,5 +35,6 @@ services: db: condition: service_healthy env_file: - - ./config/docker/env/fineract-mariadb.env - ./config/docker/env/fineract.env + - ./config/docker/env/fineract-common.env + - ./config/docker/env/fineract-mariadb.env diff --git a/fineract-client/build.gradle b/fineract-client/build.gradle index 5c7bc6531..6fd0185a8 100644 --- a/fineract-client/build.gradle +++ b/fineract-client/build.gradle @@ -16,9 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -plugins { - id 'org.openapi.generator' version '6.6.0' -} +apply plugin: 'org.openapi.generator' description = 'Fineract Client' apply from: 'dependencies.gradle' diff --git a/fineract-client/dependencies.gradle b/fineract-client/dependencies.gradle index 62f7b8b58..e5bf65e9c 100644 --- a/fineract-client/dependencies.gradle +++ b/fineract-client/dependencies.gradle @@ -21,7 +21,6 @@ dependencies { // only handles javax annotations, not jakarta ones implementation 'jakarta.annotation:jakarta.annotation-api:1.3.5' - implementation( 'io.swagger.core.v3:swagger-annotations-jakarta', 'com.squareup.retrofit2:retrofit', @@ -31,6 +30,8 @@ dependencies { 'com.squareup.retrofit2:converter-gson', 'io.gsonfire:gson-fire', 'com.google.code.findbugs:jsr305', + 'com.github.spotbugs:spotbugs-annotations', + 'com.squareup.okhttp3:okhttp', 'com.squareup.okhttp3:logging-interceptor', ) diff --git a/fineract-client/src/test/java/org/apache/fineract/client/test/FineractClientDemo.java b/fineract-client/src/test/java/org/apache/fineract/client/test/FineractClientDemo.java index 316240bb4..0a3d7ec96 100644 --- a/fineract-client/src/test/java/org/apache/fineract/client/test/FineractClientDemo.java +++ b/fineract-client/src/test/java/org/apache/fineract/client/test/FineractClientDemo.java @@ -22,6 +22,8 @@ import java.util.List; import org.apache.fineract.client.models.RetrieveOneResponse; import org.apache.fineract.client.util.Calls; import org.apache.fineract.client.util.FineractClient; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Demo code which is included in the fineract-doc/src/docs/en/05_client.adoc. @@ -33,12 +35,15 @@ import org.apache.fineract.client.util.FineractClient; */ public class FineractClientDemo { + private static final Logger log = LoggerFactory.getLogger(FineractClientDemo.class); + void demoClient() { // tag::documentation[] FineractClient fineract = FineractClient.builder().baseURL("https://demo.fineract.dev/fineract-provider/api/v1/").tenant("default") .basicAuth("mifos", "password").build(); List staff = Calls.ok(fineract.staff.retrieveAll16(1L, true, false, "ACTIVE")); String name = staff.get(0).getDisplayName(); + log.info("Display name: {}", name); // end::documentation[] } diff --git a/fineract-client/src/test/java/org/apache/fineract/client/test/FineractClientTechnicalTest.java b/fineract-client/src/test/java/org/apache/fineract/client/test/FineractClientTechnicalTest.java index b369bec3a..f45b3712f 100644 --- a/fineract-client/src/test/java/org/apache/fineract/client/test/FineractClientTechnicalTest.java +++ b/fineract-client/src/test/java/org/apache/fineract/client/test/FineractClientTechnicalTest.java @@ -20,6 +20,7 @@ package org.apache.fineract.client.test; import static org.junit.jupiter.api.Assertions.assertThrows; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import org.apache.fineract.client.util.FineractClient; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; @@ -29,6 +30,7 @@ import org.junit.jupiter.api.Test; * * @author Michael Vorburger.ch */ +@SuppressFBWarnings(value = "RV_EXCEPTION_NOT_THROWN", justification = "False positive") public class FineractClientTechnicalTest { @Test diff --git a/fineract-core/dependencies.gradle b/fineract-core/dependencies.gradle index 3bbde9d03..b7bab1d2c 100644 --- a/fineract-core/dependencies.gradle +++ b/fineract-core/dependencies.gradle @@ -53,7 +53,7 @@ dependencies { 'org.springdoc:springdoc-openapi-starter-webmvc-ui', 'org.mapstruct:mapstruct', - 'io.github.resilience4j:resilience4j-spring-boot2', + 'io.github.resilience4j:resilience4j-spring-boot3', 'org.apache.httpcomponents:httpcore', ) implementation ('org.springframework.boot:spring-boot-starter-data-jpa') { diff --git a/fineract-core/src/main/java/org/apache/fineract/accounting/closure/api/GLClosuresApiResource.java b/fineract-core/src/main/java/org/apache/fineract/accounting/closure/api/GLClosuresApiResource.java index 95c8d4a7e..e9d2e545b 100644 --- a/fineract-core/src/main/java/org/apache/fineract/accounting/closure/api/GLClosuresApiResource.java +++ b/fineract-core/src/main/java/org/apache/fineract/accounting/closure/api/GLClosuresApiResource.java @@ -70,7 +70,7 @@ public class GLClosuresApiResource { Arrays.asList("id", "officeId", "officeName", "closingDate", "deleted", "createdDate", "lastUpdatedDate", "createdByUserId", "createdByUsername", "lastUpdatedByUserId", "lastUpdatedByUsername")); - private final String resourceNameForPermission = "GLCLOSURE"; + private static final String RESOURCE_NAME_FOR_PERMISSION = "GLCLOSURE"; private final PlatformSecurityContext context; private final GLClosureReadPlatformService glClosureReadPlatformService; @@ -88,7 +88,7 @@ public class GLClosuresApiResource { public String retrieveAllClosures(@Context final UriInfo uriInfo, @QueryParam("officeId") @Parameter(name = "officeId") final Long officeId) { - this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermission); + this.context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSION); final List glClosureDatas = this.glClosureReadPlatformService.retrieveAllGLClosures(officeId); final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); @@ -106,7 +106,7 @@ public class GLClosuresApiResource { public String retreiveClosure(@PathParam("glClosureId") @Parameter(description = "glClosureId") final Long glClosureId, @Context final UriInfo uriInfo) { - this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermission); + this.context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSION); final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); diff --git a/fineract-core/src/main/java/org/apache/fineract/accounting/glaccount/api/GLAccountsApiResource.java b/fineract-core/src/main/java/org/apache/fineract/accounting/glaccount/api/GLAccountsApiResource.java index e4b51b092..2bbd839dd 100644 --- a/fineract-core/src/main/java/org/apache/fineract/accounting/glaccount/api/GLAccountsApiResource.java +++ b/fineract-core/src/main/java/org/apache/fineract/accounting/glaccount/api/GLAccountsApiResource.java @@ -85,7 +85,7 @@ public class GLAccountsApiResource { "allowedAssetsTagOptions", "allowedLiabilitiesTagOptions", "allowedEquityTagOptions", "allowedIncomeTagOptions", "allowedExpensesTagOptions", "creditAccounts", "debitAccounts")); - private final String resourceNameForPermission = "GLACCOUNT"; + private static final String RESOURCE_NAME_FOR_PERMISSION = "GLACCOUNT"; private final PlatformSecurityContext context; private final GLAccountReadPlatformService glAccountReadPlatformService; @@ -111,7 +111,7 @@ public class GLAccountsApiResource { public String retrieveNewAccountDetails(@Context final UriInfo uriInfo, @QueryParam("type") @Parameter(description = "type") final Integer type) { - this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermission); + this.context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSION); GLAccountData glAccountData = this.glAccountReadPlatformService.retrieveNewGLAccountDetails(type); glAccountData = handleTemplate(glAccountData); @@ -137,7 +137,7 @@ public class GLAccountsApiResource { @QueryParam("disabled") @Parameter(description = "disabled") final Boolean disabled, @QueryParam("fetchRunningBalance") @Parameter(description = "fetchRunningBalance") final boolean runningBalance) { - this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermission); + this.context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSION); JournalEntryAssociationParametersData associationParametersData = new JournalEntryAssociationParametersData(false, runningBalance); final List glAccountDatas = this.glAccountReadPlatformService.retrieveAllGLAccounts(type, searchParam, usage, manualEntriesAllowed, disabled, associationParametersData); @@ -159,7 +159,7 @@ public class GLAccountsApiResource { @Context final UriInfo uriInfo, @QueryParam("fetchRunningBalance") @Parameter(description = "fetchRunningBalance") final boolean runningBalance) { - this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermission); + this.context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSION); final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); JournalEntryAssociationParametersData associationParametersData = new JournalEntryAssociationParametersData(false, runningBalance); diff --git a/fineract-core/src/main/java/org/apache/fineract/accounting/glaccount/domain/GLAccountType.java b/fineract-core/src/main/java/org/apache/fineract/accounting/glaccount/domain/GLAccountType.java index 4f86f9748..79814b25b 100644 --- a/fineract-core/src/main/java/org/apache/fineract/accounting/glaccount/domain/GLAccountType.java +++ b/fineract-core/src/main/java/org/apache/fineract/accounting/glaccount/domain/GLAccountType.java @@ -18,8 +18,6 @@ */ package org.apache.fineract.accounting.glaccount.domain; -import java.util.HashMap; -import java.util.Map; import org.apache.fineract.infrastructure.core.data.EnumOptionData; public enum GLAccountType { @@ -43,7 +41,6 @@ public enum GLAccountType { return this.code; } - private static final Map intToEnumMap = new HashMap<>(); private static int minValue; private static int maxValue; @@ -53,7 +50,6 @@ public enum GLAccountType { if (i == 0) { minValue = type.value; } - intToEnumMap.put(type.value, type); if (minValue >= type.value) { minValue = type.value; } @@ -86,9 +82,25 @@ public enum GLAccountType { } } - public static GLAccountType fromInt(final int i) { - final GLAccountType type = intToEnumMap.get(Integer.valueOf(i)); - return type; + public static GLAccountType fromInt(final Integer v) { + if (v == null) { + return null; + } + + switch (v) { + case 1: + return ASSET; + case 2: + return LIABILITY; + case 3: + return EQUITY; + case 4: + return INCOME; + case 5: + return EXPENSE; + default: + return null; + } } public static int getMinValue() { diff --git a/fineract-core/src/main/java/org/apache/fineract/accounting/glaccount/service/GLAccountWritePlatformServiceJpaRepositoryImpl.java b/fineract-core/src/main/java/org/apache/fineract/accounting/glaccount/service/GLAccountWritePlatformServiceJpaRepositoryImpl.java index 23933693d..cc672fc71 100644 --- a/fineract-core/src/main/java/org/apache/fineract/accounting/glaccount/service/GLAccountWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-core/src/main/java/org/apache/fineract/accounting/glaccount/service/GLAccountWritePlatformServiceJpaRepositoryImpl.java @@ -170,8 +170,8 @@ public class GLAccountWritePlatformServiceJpaRepositoryImpl implements GLAccount private void validateForAttachedProduct(Long glAccountId) { String sql = "select count(*) from acc_product_mapping acc where acc.gl_account_id = ?"; try { - int count = this.jdbcTemplate.queryForObject(sql, Integer.class, glAccountId); - if (count > 0) { + Integer count = this.jdbcTemplate.queryForObject(sql, Integer.class, glAccountId); + if (count == null || count > 0) { throw new GLAccountDisableException(); } } catch (EmptyResultDataAccessException e) { diff --git a/fineract-core/src/main/java/org/apache/fineract/accounting/journalentry/domain/JournalEntryType.java b/fineract-core/src/main/java/org/apache/fineract/accounting/journalentry/domain/JournalEntryType.java index 52f03220a..80b9b49af 100755 --- a/fineract-core/src/main/java/org/apache/fineract/accounting/journalentry/domain/JournalEntryType.java +++ b/fineract-core/src/main/java/org/apache/fineract/accounting/journalentry/domain/JournalEntryType.java @@ -18,9 +18,6 @@ */ package org.apache.fineract.accounting.journalentry.domain; -import java.util.HashMap; -import java.util.Map; - public enum JournalEntryType { CREDIT(1, "journalEntryType.credit"), DEBIT(2, "journalEntrytType.debit"); @@ -41,16 +38,19 @@ public enum JournalEntryType { return this.code; } - private static final Map intToEnumMap = new HashMap<>(); - - static { - for (final JournalEntryType type : JournalEntryType.values()) { - intToEnumMap.put(type.value, type); + public static JournalEntryType fromInt(final Integer v) { + if (v == null) { + return null; } - } - public static JournalEntryType fromInt(final int i) { - return intToEnumMap.get(i); + switch (v) { + case 1: + return CREDIT; + case 2: + return DEBIT; + default: + return null; + } } @Override @@ -59,11 +59,11 @@ public enum JournalEntryType { } public boolean isDebitType() { - return this.value.equals(JournalEntryType.DEBIT.getValue()); + return this.equals(DEBIT); } public boolean isCreditType() { - return this.value.equals(JournalEntryType.CREDIT.getValue()); + return this.equals(CREDIT); } } diff --git a/fineract-core/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/domain/PortfolioProductType.java b/fineract-core/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/domain/PortfolioProductType.java index d233e73f2..0826a4c04 100644 --- a/fineract-core/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/domain/PortfolioProductType.java +++ b/fineract-core/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/domain/PortfolioProductType.java @@ -18,9 +18,6 @@ */ package org.apache.fineract.accounting.producttoaccountmapping.domain; -import java.util.HashMap; -import java.util.Map; - public enum PortfolioProductType { LOAN(1, "productType.loan"), SAVING(2, "productType.saving"), CLIENT(5, "productType.client"), PROVISIONING(3, @@ -47,33 +44,41 @@ public enum PortfolioProductType { return this.code; } - private static final Map intToEnumMap = new HashMap<>(); + public static PortfolioProductType fromInt(final Integer v) { + if (v == null) { + return null; + } - static { - for (final PortfolioProductType type : PortfolioProductType.values()) { - intToEnumMap.put(type.value, type); + switch (v) { + case 1: + return LOAN; + case 2: + return SAVING; + case 3: + return CLIENT; + case 4: + return PROVISIONING; + case 5: + return SHARES; + default: + return null; } } - public static PortfolioProductType fromInt(final int i) { - final PortfolioProductType type = intToEnumMap.get(Integer.valueOf(i)); - return type; - } - public boolean isSavingProduct() { - return this.value.equals(PortfolioProductType.SAVING.getValue()); + return this.equals(SAVING); } public boolean isLoanProduct() { - return this.value.equals(PortfolioProductType.LOAN.getValue()); + return this.equals(LOAN); } public boolean isClient() { - return this.value.equals(PortfolioProductType.CLIENT.getValue()); + return this.equals(CLIENT); } public boolean isShareProduct() { - return this.value.equals(PortfolioProductType.SHARES.getValue()); + return this.equals(SHARES); } } diff --git a/fineract-core/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/service/ProductToGLAccountMappingHelper.java b/fineract-core/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/service/ProductToGLAccountMappingHelper.java index 3ae49657e..0e895bb9d 100644 --- a/fineract-core/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/service/ProductToGLAccountMappingHelper.java +++ b/fineract-core/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/service/ProductToGLAccountMappingHelper.java @@ -26,6 +26,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import lombok.RequiredArgsConstructor; import org.apache.fineract.accounting.common.AccountingConstants.CashAccountsForLoan; @@ -99,7 +100,7 @@ public class ProductToGLAccountMappingHelper { throw new ProductToGLAccountMappingNotFoundException(portfolioProductType, productId, accountTypeName); } } else { - if (!accountMapping.getGlAccount().getId().equals(accountId)) { + if (accountMapping.getGlAccount() != null && !Objects.equals(accountMapping.getGlAccount().getId(), accountId)) { final GLAccount glAccount = getAccountByIdAndType(paramName, expectedAccountType, accountId); changes.put(paramName, accountId); accountMapping.setGlAccount(glAccount); @@ -124,7 +125,7 @@ public class ProductToGLAccountMappingHelper { ProductToGLAccountMapping newAccountMapping = new ProductToGLAccountMapping().setGlAccount(glAccount) .setProductId(productId).setProductType(portfolioProductType.getValue()).setFinancialAccountType(accountTypeId); this.accountMappingRepository.saveAndFlush(newAccountMapping); - } else if (!accountMapping.getGlAccount().getId().equals(accountId)) { + } else if (accountMapping.getGlAccount() != null && !Objects.equals(accountMapping.getGlAccount().getId(), accountId)) { final GLAccount glAccount = getAccountByIdAndType(paramName, expectedAccountType, accountId); changes.put(paramName, accountId); accountMapping.setGlAccount(glAccount); @@ -272,14 +273,11 @@ public class ProductToGLAccountMappingHelper { this.accountMappingRepository.delete(chargeToIncomeAccountMapping); } } - // create new mappings - final Set incomingCharges = inputChargeToIncomeAccountMap.keySet(); - incomingCharges.removeAll(existingCharges); - // incomingPaymentTypes now only contains the newly added - // payment Type mappings - for (final Long newCharge : incomingCharges) { - final Long newGLAccountId = inputChargeToIncomeAccountMap.get(newCharge); - saveChargeToFundSourceMapping(productId, newCharge, newGLAccountId, portfolioProductType, isPenalty); + + // only the newly added + for (Map.Entry entry : inputChargeToIncomeAccountMap.entrySet().stream() + .filter(e -> !existingCharges.contains(e.getKey())).toList()) { + saveChargeToFundSourceMapping(productId, entry.getKey(), entry.getValue(), portfolioProductType, isPenalty); } } } @@ -321,7 +319,7 @@ public class ProductToGLAccountMappingHelper { } // If input map is empty, delete all existing mappings - if (inputPaymentChannelFundSourceMap.size() == 0) { + if (inputPaymentChannelFundSourceMap.isEmpty()) { this.accountMappingRepository.deleteAllInBatch(existingPaymentChannelToFundSourceMappings); } /** * Else,
@@ -348,14 +346,11 @@ public class ProductToGLAccountMappingHelper { this.accountMappingRepository.delete(existingPaymentChannelToFundSourceMapping); } } - // create new mappings - final Set incomingPaymentTypes = inputPaymentChannelFundSourceMap.keySet(); - incomingPaymentTypes.removeAll(existingPaymentTypes); - // incomingPaymentTypes now only contains the newly added - // payment Type mappings - for (final Long newPaymentType : incomingPaymentTypes) { - final Long newGLAccountId = inputPaymentChannelFundSourceMap.get(newPaymentType); - savePaymentChannelToFundSourceMapping(productId, newPaymentType, newGLAccountId, portfolioProductType); + + // only the newly added + for (Map.Entry entry : inputPaymentChannelFundSourceMap.entrySet().stream() + .filter(e -> !existingPaymentTypes.contains(e.getKey())).toList()) { + savePaymentChannelToFundSourceMapping(productId, entry.getKey(), entry.getValue(), portfolioProductType); } } } diff --git a/fineract-core/src/main/java/org/apache/fineract/batch/api/BatchApiResource.java b/fineract-core/src/main/java/org/apache/fineract/batch/api/BatchApiResource.java index 6eb189880..d8cb1b81b 100644 --- a/fineract-core/src/main/java/org/apache/fineract/batch/api/BatchApiResource.java +++ b/fineract-core/src/main/java/org/apache/fineract/batch/api/BatchApiResource.java @@ -37,7 +37,6 @@ import jakarta.ws.rs.QueryParam; import jakarta.ws.rs.core.Context; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.UriInfo; -import java.util.ArrayList; import java.util.List; import java.util.Optional; import lombok.RequiredArgsConstructor; @@ -112,7 +111,7 @@ public class BatchApiResource { validateRequestMethodsAllowedOnInstanceType(requestList); // Gets back the consolidated BatchResponse from BatchApiservice - List result = new ArrayList<>(); + List result; // If the request is to be handled as a Transaction. All requests will // be rolled back on error diff --git a/fineract-core/src/main/java/org/apache/fineract/batch/service/BatchApiServiceImpl.java b/fineract-core/src/main/java/org/apache/fineract/batch/service/BatchApiServiceImpl.java index a7d799ada..0339cee1b 100644 --- a/fineract-core/src/main/java/org/apache/fineract/batch/service/BatchApiServiceImpl.java +++ b/fineract-core/src/main/java/org/apache/fineract/batch/service/BatchApiServiceImpl.java @@ -23,6 +23,7 @@ import static org.apache.http.HttpStatus.SC_OK; import com.google.gson.Gson; import com.jayway.jsonpath.JsonPathException; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import io.github.resilience4j.core.functions.Either; import jakarta.persistence.EntityManager; import jakarta.persistence.PersistenceContext; @@ -380,6 +381,7 @@ public class BatchApiServiceImpl implements BatchApiService { return List.of(buildErrorResponse(requestId, statusCode, body, headers)); } + @SuppressFBWarnings(value = "BX_UNBOXING_IMMEDIATELY_REBOXED", justification = "TODO: fix this!") private BatchResponse buildErrorResponse(Long requestId, Integer statusCode, String body, Set
headers) { return new BatchResponse().setRequestId(requestId).setStatusCode(statusCode == null ? SC_INTERNAL_SERVER_ERROR : statusCode) .setBody(body == null ? "Request with id " + requestId + " was erroneous!" : body).setHeaders(headers); diff --git a/fineract-core/src/main/java/org/apache/fineract/commands/provider/CommandHandlerProvider.java b/fineract-core/src/main/java/org/apache/fineract/commands/provider/CommandHandlerProvider.java index a4297f9d5..38ca3e705 100644 --- a/fineract-core/src/main/java/org/apache/fineract/commands/provider/CommandHandlerProvider.java +++ b/fineract-core/src/main/java/org/apache/fineract/commands/provider/CommandHandlerProvider.java @@ -65,7 +65,11 @@ public class CommandHandlerProvider implements ApplicationContextAware, Initiali log.debug("Register command handler '{}' ...", commandHandlerName); final CommandType commandType = applicationContext.findAnnotationOnBean(commandHandlerName, CommandType.class); try { - registeredHandlers.put(commandType.entity() + "|" + commandType.action(), commandHandlerName); + if (commandType != null) { + registeredHandlers.put(commandType.entity() + "|" + commandType.action(), commandHandlerName); + } else { + log.error("Unable to register command handler '{}'!", commandHandlerName); + } } catch (final Throwable th) { log.error("Unable to register command handler '{}'!", commandHandlerName, th); } diff --git a/fineract-core/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java b/fineract-core/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java index 486abf6c9..88646406c 100644 --- a/fineract-core/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java +++ b/fineract-core/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java @@ -18,6 +18,7 @@ */ package org.apache.fineract.commands.service; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import org.apache.fineract.commands.domain.CommandWrapper; import org.apache.fineract.infrastructure.accountnumberformat.service.AccountNumberFormatConstants; import org.apache.fineract.portfolio.client.api.ClientApiConstants; @@ -47,6 +48,7 @@ public class CommandWrapperBuilder { private String jobName; private String idempotencyKey; + @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "TODO: fix this!") public CommandWrapper build() { return new CommandWrapper(this.officeId, this.groupId, this.clientId, this.loanId, this.savingsId, this.actionName, this.entityName, this.entityId, this.subentityId, this.href, this.json, this.transactionId, this.productId, this.templateId, diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/cache/service/RuntimeDelegatingCacheManager.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/cache/service/RuntimeDelegatingCacheManager.java index a15ae0130..f2d3b4e97 100644 --- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/cache/service/RuntimeDelegatingCacheManager.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/cache/service/RuntimeDelegatingCacheManager.java @@ -18,10 +18,12 @@ */ package org.apache.fineract.infrastructure.cache.service; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.Map; +import java.util.Objects; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.fineract.infrastructure.cache.CacheApiConstants; @@ -105,7 +107,7 @@ public class RuntimeDelegatingCacheManager implements CacheManager, Initializing } currentCacheManager = ehCacheManager; - if (currentCacheManager.getCacheNames().size() == 0) { + if (currentCacheManager.getCacheNames().isEmpty()) { log.error("No caches configured for activated CacheManager {}", currentCacheManager); } } @@ -115,10 +117,17 @@ public class RuntimeDelegatingCacheManager implements CacheManager, Initializing return changes; } + @SuppressFBWarnings(value = "DCN_NULLPOINTER_EXCEPTION", justification = "TODO: fix this!") private void clearEhCache() { Iterable cacheNames = ehCacheManager.getCacheNames(); for (String cacheName : cacheNames) { - ehCacheManager.getCache(cacheName).clear(); + try { + if (Objects.nonNull(ehCacheManager.getCache(cacheName))) { + Objects.requireNonNull(ehCacheManager.getCache(cacheName)).clear(); + } + } catch (NullPointerException npe) { + log.warn(npe.getMessage()); + } } } } diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/config/FineractProperties.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/config/FineractProperties.java index 5f80f69cd..0e0b57de8 100644 --- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/config/FineractProperties.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/config/FineractProperties.java @@ -38,6 +38,8 @@ public class FineractProperties { private String idempotencyKeyHeaderName; + private Boolean insecureHttpClient; + private FineractTenantProperties tenant; private FineractModeProperties mode; diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exception/IdempotentCommandProcessFailedException.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exception/IdempotentCommandProcessFailedException.java index 0ea52b8fb..bd0f969fd 100644 --- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exception/IdempotentCommandProcessFailedException.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exception/IdempotentCommandProcessFailedException.java @@ -39,6 +39,6 @@ public class IdempotentCommandProcessFailedException extends AbstractIdempotentC @NotNull public Integer getStatusCode() { // If the database inconsistent we return http 500 instead of null pointer exception - return statusCode == null ? SC_INTERNAL_SERVER_ERROR : statusCode; + return statusCode == null ? Integer.valueOf(SC_INTERNAL_SERVER_ERROR) : statusCode; } } diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/serialization/JsonParserHelper.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/serialization/JsonParserHelper.java index 0074442ef..a3cd2bd41 100644 --- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/serialization/JsonParserHelper.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/serialization/JsonParserHelper.java @@ -736,6 +736,7 @@ public class JsonParserHelper { /*** * TODO: Vishwas move all Locale related code to a separate Utils class ***/ + @SuppressWarnings("StringSplitter") public static Locale localeFromString(final String localeAsString) { if (StringUtils.isBlank(localeAsString)) { @@ -754,16 +755,16 @@ public class JsonParserHelper { final String[] localeParts = localeAsString.split("_"); - if (localeParts != null && localeParts.length == 1) { + if (localeParts.length == 1) { languageCode = localeParts[0]; } - if (localeParts != null && localeParts.length == 2) { + if (localeParts.length == 2) { languageCode = localeParts[0]; countryCode = localeParts[1]; } - if (localeParts != null && localeParts.length == 3) { + if (localeParts.length == 3) { languageCode = localeParts[0]; countryCode = localeParts[1]; variantCode = localeParts[2]; diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/Page.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/Page.java index a7bf95d93..76755e4b5 100644 --- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/Page.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/Page.java @@ -23,10 +23,10 @@ import java.util.List; public class Page implements Serializable { - private final int totalFilteredRecords; + private final Integer totalFilteredRecords; private final List pageItems; - public Page(final List pageItems, final int totalFilteredRecords) { + public Page(final List pageItems, final Integer totalFilteredRecords) { this.pageItems = pageItems; this.totalFilteredRecords = totalFilteredRecords; } diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/PagedLocalRequest.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/PagedLocalRequest.java index b2c645442..5289850cc 100644 --- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/PagedLocalRequest.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/PagedLocalRequest.java @@ -19,6 +19,7 @@ package org.apache.fineract.infrastructure.core.service; import java.util.Locale; +import java.util.Objects; import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.Setter; @@ -38,4 +39,25 @@ public class PagedLocalRequest extends PagedRequest { public Locale getLocaleObject() { return locale == null ? null : JsonParserHelper.localeFromString(locale); } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || !(o instanceof PagedLocalRequest)) { + return false; + } + if (!super.equals(o)) { + return false; + } + PagedLocalRequest that = (PagedLocalRequest) o; + return Objects.equals(dateFormat, that.dateFormat) && Objects.equals(dateTimeFormat, that.dateTimeFormat) + && Objects.equals(locale, that.locale); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), dateFormat, dateTimeFormat, locale); + } } diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/PagedRequest.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/PagedRequest.java index e2becbb50..b87e4d308 100644 --- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/PagedRequest.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/PagedRequest.java @@ -37,7 +37,7 @@ public class PagedRequest { private int page; private int size = DEFAULT_PAGE_SIZE; - private List sorts = new ArrayList<>(); + private final List sorts = new ArrayList<>(); public Optional getRequest() { return Optional.ofNullable(request); diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/PaginationHelper.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/PaginationHelper.java index 2787aada3..51b394b15 100644 --- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/PaginationHelper.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/PaginationHelper.java @@ -45,7 +45,7 @@ public class PaginationHelper { // determine how many rows are available final String sqlCountRows = sqlGenerator.countLastExecutedQueryResult(sqlFetchRows); - final int totalFilteredRecords; + final Integer totalFilteredRecords; if (databaseTypeResolver.isMySQL()) { totalFilteredRecords = jt.queryForObject(sqlCountRows, Integer.class); // NOSONAR } else { diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/database/JavaType.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/database/JavaType.java index 56b31d236..3d1536c7b 100644 --- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/database/JavaType.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/database/JavaType.java @@ -91,9 +91,7 @@ public enum JavaType { OBJECT(Object.class), // ; - public static final JavaType[] VALUES = values(); - - private static final Map, JavaType> BY_TYPE = Arrays.stream(VALUES).filter(e -> e.type != null) + private static final Map, JavaType> BY_TYPE = Arrays.stream(values()).filter(e -> e.type != null) .collect(Collectors.toMap(JavaType::getTypeClass, v -> v)); private final Class type; @@ -244,9 +242,9 @@ public enum JavaType { // have to do this first to catch custom collection and map types; // on resolve we figure out if these custom types are // persistence-capable - for (Class aType : BY_TYPE.keySet()) { - if (aType.isAssignableFrom(type)) { - return BY_TYPE.get(aType); + for (Map.Entry, JavaType> entry : BY_TYPE.entrySet()) { + if (entry.getKey().isAssignableFrom(type)) { + return entry.getValue(); } } diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/database/JdbcJavaType.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/database/JdbcJavaType.java index aea1339f6..2eb35d22e 100644 --- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/database/JdbcJavaType.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/database/JdbcJavaType.java @@ -136,11 +136,19 @@ public enum JdbcJavaType { for (JdbcJavaType type : values()) { DialectType dialectType = type.getDialectType(dialect); if (dialectType.getNameResolved().equals(name)) { + // NOTE: make MySQL systems happy aka TINYINT vs BOOLEAN issue! + if (type.canBooleanType(dialect)) { + return BOOLEAN; + } return type; } if (dialectType.alterNames != null) { for (String alterName : dialectType.alterNames) { if (alterName.equals(name)) { + // NOTE: make MySQL systems happy aka TINYINT vs BOOLEAN issue! + if (type.canBooleanType(dialect)) { + return BOOLEAN; + } return type; } } diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/event/external/service/ExternalEventConfigurationWritePlatformServiceImpl.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/event/external/service/ExternalEventConfigurationWritePlatformServiceImpl.java index 77e279303..ddaec0514 100644 --- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/event/external/service/ExternalEventConfigurationWritePlatformServiceImpl.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/event/external/service/ExternalEventConfigurationWritePlatformServiceImpl.java @@ -48,14 +48,15 @@ public class ExternalEventConfigurationWritePlatformServiceImpl implements Exter final Map changes = new HashMap<>(); final Map changedConfigurations = new HashMap<>(); final List modifiedConfigurations = new ArrayList<>(); - for (final String eventType : commandConfigurations.keySet()) { + + for (Map.Entry entry : commandConfigurations.entrySet()) { final ExternalEventConfiguration configuration = repository - .findExternalEventConfigurationByTypeWithNotFoundDetection(eventType); - final boolean canEnable = commandConfigurations.get(eventType).booleanValue(); - configuration.setEnabled(canEnable); - changedConfigurations.put(eventType, canEnable); + .findExternalEventConfigurationByTypeWithNotFoundDetection(entry.getKey()); + configuration.setEnabled(entry.getValue()); + changedConfigurations.put(entry.getKey(), entry.getValue()); modifiedConfigurations.add(configuration); } + if (!modifiedConfigurations.isEmpty()) { this.repository.saveAll(modifiedConfigurations); } diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/security/utils/ColumnValidator.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/security/utils/ColumnValidator.java index f3c63de8b..cf5c2ee86 100644 --- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/security/utils/ColumnValidator.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/security/utils/ColumnValidator.java @@ -18,6 +18,7 @@ */ package org.apache.fineract.infrastructure.security.utils; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.ResultSet; @@ -28,6 +29,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; @@ -48,17 +50,18 @@ public class ColumnValidator { this.jdbcTemplate = jdbcTemplate; } + @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "TODO: fix this!") private void validateColumn(Map> tableColumnMap) { Connection connection = null; + try { - connection = this.jdbcTemplate.getDataSource().getConnection(); + connection = Objects.requireNonNull(this.jdbcTemplate.getDataSource()).getConnection(); DatabaseMetaData dbMetaData = connection.getMetaData(); - ResultSet resultSet = null; for (Map.Entry> entry : tableColumnMap.entrySet()) { Set columns = entry.getValue(); - resultSet = dbMetaData.getColumns(null, null, entry.getKey(), null); + ResultSet resultSet = dbMetaData.getColumns(null, null, entry.getKey(), null); Set tableColumns = getTableColumns(resultSet); - if (columns.size() > 0 && tableColumns.size() == 0) { + if (!columns.isEmpty() && tableColumns.isEmpty()) { throw new SQLInjectionException(); } for (String requestedColumn : columns) { @@ -111,17 +114,19 @@ public class ColumnValidator { private static Map> getTableColumnMap(String schema, Map> tableColumnAliasMap) { Map> tableColumnMap = new HashMap<>(); schema = schema.substring(schema.indexOf("from")); - for (String alias : tableColumnAliasMap.keySet()) { - int index = schema.indexOf(" " + alias + " "); + + for (Map.Entry> entry : tableColumnAliasMap.entrySet()) { + int index = schema.indexOf(" " + entry.getKey() + " "); if (index > -1) { - int startPos = 0; + int startPos; startPos = schema.substring(0, index - 1).lastIndexOf(' ', index); - Set columns = tableColumnAliasMap.get(alias); + Set columns = entry.getValue(); tableColumnMap.put(schema.substring(startPos, index).trim(), columns); } else { throw new SQLInjectionException(); } } + return tableColumnMap; } diff --git a/fineract-core/src/main/java/org/apache/fineract/organisation/holiday/domain/HolidayStatusType.java b/fineract-core/src/main/java/org/apache/fineract/organisation/holiday/domain/HolidayStatusType.java index 85abe07a6..b07d29932 100644 --- a/fineract-core/src/main/java/org/apache/fineract/organisation/holiday/domain/HolidayStatusType.java +++ b/fineract-core/src/main/java/org/apache/fineract/organisation/holiday/domain/HolidayStatusType.java @@ -31,20 +31,21 @@ public enum HolidayStatusType { private final Integer value; private final String code; - public static HolidayStatusType fromInt(final Integer type) { - HolidayStatusType enumeration = HolidayStatusType.INVALID; - switch (type) { + public static HolidayStatusType fromInt(final Integer v) { + if (v == null) { + return INVALID; + } + + switch (v) { case 100: - enumeration = HolidayStatusType.PENDING_FOR_ACTIVATION; - break; + return PENDING_FOR_ACTIVATION; case 300: - enumeration = HolidayStatusType.ACTIVE; - break; + return ACTIVE; case 600: - enumeration = HolidayStatusType.DELETED; - break; + return DELETED; + default: + return INVALID; } - return enumeration; } HolidayStatusType(final Integer value, final String code) { @@ -52,10 +53,6 @@ public enum HolidayStatusType { this.code = code; } - public boolean hasStateOf(final HolidayStatusType state) { - return this.value.equals(state.getValue()); - } - public Integer getValue() { return this.value; } diff --git a/fineract-core/src/main/java/org/apache/fineract/organisation/holiday/domain/RescheduleType.java b/fineract-core/src/main/java/org/apache/fineract/organisation/holiday/domain/RescheduleType.java index 6a9e8e3cb..ea165f194 100644 --- a/fineract-core/src/main/java/org/apache/fineract/organisation/holiday/domain/RescheduleType.java +++ b/fineract-core/src/main/java/org/apache/fineract/organisation/holiday/domain/RescheduleType.java @@ -31,17 +31,19 @@ public enum RescheduleType { this.code = code; } - public static RescheduleType fromInt(int rescheduleTypeValue) { - RescheduleType enumerration = RescheduleType.INVALID; - switch (rescheduleTypeValue) { + public static RescheduleType fromInt(final Integer v) { + if (v == null) { + return INVALID; + } + + switch (v) { case 1: - enumerration = RescheduleType.RESCHEDULETONEXTREPAYMENTDATE; - break; + return RESCHEDULETONEXTREPAYMENTDATE; case 2: - enumerration = RescheduleType.RESCHEDULETOSPECIFICDATE; - break; + return RESCHEDULETOSPECIFICDATE; + default: + return INVALID; } - return enumerration; } public boolean isRescheduleToSpecificDate() { diff --git a/fineract-core/src/main/java/org/apache/fineract/portfolio/account/PortfolioAccountType.java b/fineract-core/src/main/java/org/apache/fineract/portfolio/account/PortfolioAccountType.java index 6c2108d09..e70dfab54 100644 --- a/fineract-core/src/main/java/org/apache/fineract/portfolio/account/PortfolioAccountType.java +++ b/fineract-core/src/main/java/org/apache/fineract/portfolio/account/PortfolioAccountType.java @@ -18,9 +18,6 @@ */ package org.apache.fineract.portfolio.account; -import java.util.ArrayList; -import java.util.List; - public enum PortfolioAccountType { INVALID(0, "accountType.invalid"), // @@ -43,20 +40,9 @@ public enum PortfolioAccountType { return this.code; } - public static Object[] integerValues() { - final List values = new ArrayList<>(); - for (final PortfolioAccountType enumType : values()) { - if (enumType.getValue() > 0) { - values.add(enumType.getValue()); - } - } - - return values.toArray(); - } - public static PortfolioAccountType fromInt(final Integer type) { - PortfolioAccountType enumType = PortfolioAccountType.INVALID; + PortfolioAccountType enumType = INVALID; if (type != null) { switch (type) { case 1: @@ -65,16 +51,20 @@ public enum PortfolioAccountType { case 2: enumType = SAVINGS; break; + default: + enumType = INVALID; } } return enumType; } + // TODO: bad practice and unnecessary code! why not just use the enum values themselves!?! public boolean isSavingsAccount() { - return this.value.equals(2); + return this.equals(SAVINGS); } + // TODO: bad practice and unnecessary code! why not just use the enum values themselves!?! public boolean isLoanAccount() { - return this.value.equals(1); + return this.equals(LOAN); } } diff --git a/fineract-core/src/main/java/org/apache/fineract/portfolio/calendar/service/CalendarUtils.java b/fineract-core/src/main/java/org/apache/fineract/portfolio/calendar/service/CalendarUtils.java index aa9fed213..1b4f568b5 100644 --- a/fineract-core/src/main/java/org/apache/fineract/portfolio/calendar/service/CalendarUtils.java +++ b/fineract-core/src/main/java/org/apache/fineract/portfolio/calendar/service/CalendarUtils.java @@ -272,12 +272,14 @@ public final class CalendarUtils { humanReadable += " on "; final WeekDayList weekDayList = recur.getDayList(); + StringBuilder sb = new StringBuilder(); for (@SuppressWarnings("rawtypes") final Iterator iterator = weekDayList.iterator(); iterator.hasNext();) { final WeekDay weekDay = (WeekDay) iterator.next(); - humanReadable += DayNameEnum.from(weekDay.getDay().name()).getCode(); + sb.append(DayNameEnum.from(weekDay.getDay().name()).getCode()); } + humanReadable += sb.toString(); } else if (recur.getFrequency().equals(Recur.Frequency.MONTHLY)) { NumberList nthDays = recur.getSetPosList(); @@ -684,13 +686,15 @@ public final class CalendarUtils { * @return */ public static String getSqlCalendarTypeOptionsInString(final List calendarTypeOptions) { - String sqlCalendarTypeOptions = ""; - final int size = calendarTypeOptions.size(); - for (int i = 0; i < size - 1; i++) { - sqlCalendarTypeOptions += calendarTypeOptions.get(i).toString() + ","; + StringBuilder sb = new StringBuilder(); + + for (int i = 0; i < calendarTypeOptions.size() - 1; i++) { + sb.append(calendarTypeOptions.get(i).toString() + ","); } - sqlCalendarTypeOptions += calendarTypeOptions.get(size - 1).toString(); - return sqlCalendarTypeOptions; + + sb.append(calendarTypeOptions.get(calendarTypeOptions.size() - 1).toString()); + + return sb.toString(); } public static LocalDate getRecentEligibleMeetingDate(final String recurringRule, final LocalDate seedDate, diff --git a/fineract-core/src/main/java/org/apache/fineract/portfolio/common/domain/DaysInMonthType.java b/fineract-core/src/main/java/org/apache/fineract/portfolio/common/domain/DaysInMonthType.java index 32d58ccbc..20eca6bfe 100644 --- a/fineract-core/src/main/java/org/apache/fineract/portfolio/common/domain/DaysInMonthType.java +++ b/fineract-core/src/main/java/org/apache/fineract/portfolio/common/domain/DaysInMonthType.java @@ -18,8 +18,7 @@ */ package org.apache.fineract.portfolio.common.domain; -import java.util.ArrayList; -import java.util.List; +import java.util.Arrays; /** * @@ -51,15 +50,9 @@ public enum DaysInMonthType { return this.code; } + // TODO: do we really need this?!? public static Object[] integerValues() { - final List values = new ArrayList<>(); - for (final DaysInMonthType enumType : values()) { - if (enumType.getValue() > 0) { - values.add(enumType.getValue()); - } - } - - return values.toArray(); + return Arrays.stream(values()).filter(value -> !INVALID.equals(value)).map(value -> value.value).toList().toArray(); } public static DaysInMonthType fromInt(final Integer type) { diff --git a/fineract-core/src/main/java/org/apache/fineract/portfolio/common/domain/DaysInYearType.java b/fineract-core/src/main/java/org/apache/fineract/portfolio/common/domain/DaysInYearType.java index d08fff7a9..80a42d484 100644 --- a/fineract-core/src/main/java/org/apache/fineract/portfolio/common/domain/DaysInYearType.java +++ b/fineract-core/src/main/java/org/apache/fineract/portfolio/common/domain/DaysInYearType.java @@ -18,8 +18,7 @@ */ package org.apache.fineract.portfolio.common.domain; -import java.util.ArrayList; -import java.util.List; +import java.util.Arrays; /** * @@ -55,15 +54,9 @@ public enum DaysInYearType { return this.code; } + // TODO: do we really need this?!? public static Object[] integerValues() { - final List values = new ArrayList<>(); - for (final DaysInYearType enumType : values()) { - if (enumType.getValue() > 0) { - values.add(enumType.getValue()); - } - } - - return values.toArray(); + return Arrays.stream(values()).filter(value -> !INVALID.equals(value)).map(value -> value.value).toList().toArray(); } public static DaysInYearType fromInt(final Integer type) { diff --git a/fineract-core/src/main/java/org/apache/fineract/portfolio/common/domain/PeriodFrequencyType.java b/fineract-core/src/main/java/org/apache/fineract/portfolio/common/domain/PeriodFrequencyType.java index 4a4478637..f2e8561aa 100644 --- a/fineract-core/src/main/java/org/apache/fineract/portfolio/common/domain/PeriodFrequencyType.java +++ b/fineract-core/src/main/java/org/apache/fineract/portfolio/common/domain/PeriodFrequencyType.java @@ -18,8 +18,7 @@ */ package org.apache.fineract.portfolio.common.domain; -import java.util.ArrayList; -import java.util.List; +import java.util.Arrays; public enum PeriodFrequencyType { @@ -46,62 +45,59 @@ public enum PeriodFrequencyType { return this.code; } - public static PeriodFrequencyType fromInt(final Integer frequency) { - PeriodFrequencyType repaymentFrequencyType = PeriodFrequencyType.INVALID; - if (frequency != null) { - switch (frequency) { - case 0: - repaymentFrequencyType = PeriodFrequencyType.DAYS; - break; - case 1: - repaymentFrequencyType = PeriodFrequencyType.WEEKS; - break; - case 2: - repaymentFrequencyType = PeriodFrequencyType.MONTHS; - break; - case 3: - repaymentFrequencyType = PeriodFrequencyType.YEARS; - break; - case 4: - repaymentFrequencyType = PeriodFrequencyType.WHOLE_TERM; - break; - } + public static PeriodFrequencyType fromInt(final Integer v) { + if (v == null) { + return INVALID; + } + + switch (v) { + case 0: + return DAYS; + case 1: + return WEEKS; + case 2: + return MONTHS; + case 3: + return YEARS; + case 4: + return WHOLE_TERM; + default: + return INVALID; } - return repaymentFrequencyType; } + // TODO: why not just use the enum values... just more boilerplate code here!! public boolean isMonthly() { - return this.value.equals(PeriodFrequencyType.MONTHS.getValue()); + return this.equals(MONTHS); } + // TODO: why not just use the enum values... just more boilerplate code here!! public boolean isYearly() { - return this.value.equals(PeriodFrequencyType.YEARS.getValue()); + return this.equals(YEARS); } + // TODO: why not just use the enum values... just more boilerplate code here!! public boolean isWeekly() { - return this.value.equals(PeriodFrequencyType.WEEKS.getValue()); + return this.equals(WEEKS); } + // TODO: why not just use the enum values... just more boilerplate code here!! public boolean isDaily() { - return this.value.equals(PeriodFrequencyType.DAYS.getValue()); + return this.equals(DAYS); } + // TODO: why not just use the enum values... just more boilerplate code here!! public boolean isWholeTerm() { - return this.value.equals(PeriodFrequencyType.WHOLE_TERM.getValue()); + return this.equals(WHOLE_TERM); } + // TODO: why not just use the enum values... just more boilerplate code here!! public boolean isInvalid() { - return this.value.equals(PeriodFrequencyType.INVALID.getValue()); + return this.equals(INVALID); } + // TODO: do we really need this?!? public static Object[] integerValues() { - final List values = new ArrayList<>(); - for (final PeriodFrequencyType enumType : values()) { - if (!enumType.isInvalid()) { - values.add(enumType.getValue()); - } - } - - return values.toArray(); + return Arrays.stream(values()).filter(value -> !INVALID.equals(value)).map(value -> value.value).toList().toArray(); } } diff --git a/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/DepositAccountOnClosureType.java b/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/DepositAccountOnClosureType.java index aded4a028..95138389c 100644 --- a/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/DepositAccountOnClosureType.java +++ b/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/DepositAccountOnClosureType.java @@ -18,8 +18,7 @@ */ package org.apache.fineract.portfolio.savings; -import java.util.ArrayList; -import java.util.List; +import java.util.Arrays; /** * An enumeration of different options available on account closure {@link FixedDepositAccount} & @@ -49,63 +48,57 @@ public enum DepositAccountOnClosureType { return this.code; } - public static DepositAccountOnClosureType fromInt(final Integer closureTypeValue) { - - if (closureTypeValue == null) { - return DepositAccountOnClosureType.INVALID; + public static DepositAccountOnClosureType fromInt(final Integer v) { + if (v == null) { + return INVALID; } - DepositAccountOnClosureType accountOnClosureType = DepositAccountOnClosureType.INVALID; - switch (closureTypeValue) { + switch (v) { case 100: - accountOnClosureType = DepositAccountOnClosureType.WITHDRAW_DEPOSIT; - break; + return WITHDRAW_DEPOSIT; case 200: - accountOnClosureType = DepositAccountOnClosureType.TRANSFER_TO_SAVINGS; - break; + return TRANSFER_TO_SAVINGS; case 300: - accountOnClosureType = DepositAccountOnClosureType.REINVEST_PRINCIPAL_AND_INTEREST; - break; + return REINVEST_PRINCIPAL_AND_INTEREST; case 400: - accountOnClosureType = DepositAccountOnClosureType.REINVEST_PRINCIPAL_ONLY; - break; + return REINVEST_PRINCIPAL_ONLY; + default: + return INVALID; } - return accountOnClosureType; } + // TODO: why not just use the enum values... just more boilerplate code here!! public boolean isWithdarwDeposit() { - return this.value.equals(DepositAccountOnClosureType.WITHDRAW_DEPOSIT.getValue()); + return this.equals(WITHDRAW_DEPOSIT); } + // TODO: why not just use the enum values... just more boilerplate code here!! public boolean isTransferToSavings() { - return this.value.equals(DepositAccountOnClosureType.TRANSFER_TO_SAVINGS.getValue()); + return this.equals(TRANSFER_TO_SAVINGS); } + // TODO: why not just use the enum values... just more boilerplate code here!! public boolean isReinvest() { - return this.value.equals(DepositAccountOnClosureType.REINVEST_PRINCIPAL_AND_INTEREST.getValue()) - || this.value.equals(DepositAccountOnClosureType.REINVEST_PRINCIPAL_ONLY.getValue()); + return this.equals(REINVEST_PRINCIPAL_AND_INTEREST) || this.equals(REINVEST_PRINCIPAL_ONLY); } + // TODO: why not just use the enum values... just more boilerplate code here!! public boolean isReinvestPrincipal() { - return this.value.equals(DepositAccountOnClosureType.REINVEST_PRINCIPAL_ONLY.getValue()); + return this.equals(REINVEST_PRINCIPAL_ONLY); } + // TODO: why not just use the enum values... just more boilerplate code here!! public boolean isReinvestPrincipalAndInterest() { - return this.value.equals(DepositAccountOnClosureType.REINVEST_PRINCIPAL_AND_INTEREST.getValue()); + return this.equals(REINVEST_PRINCIPAL_AND_INTEREST); } + // TODO: why not just use the enum values... just more boilerplate code here!! public boolean isInvalid() { - return this.value.equals(DepositAccountOnClosureType.INVALID.getValue()); + return this.equals(INVALID); } + // TODO: do we really need this?!? public static Object[] integerValues() { - final List values = new ArrayList<>(); - for (final DepositAccountOnClosureType enumType : values()) { - if (!enumType.isInvalid()) { - values.add(enumType.getValue()); - } - } - - return values.toArray(); + return Arrays.stream(values()).filter(value -> !INVALID.equals(value)).map(value -> value.value).toList().toArray(); } } diff --git a/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/DepositAccountOnHoldTransactionType.java b/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/DepositAccountOnHoldTransactionType.java index 816d22d4c..ee293757d 100644 --- a/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/DepositAccountOnHoldTransactionType.java +++ b/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/DepositAccountOnHoldTransactionType.java @@ -43,31 +43,28 @@ public enum DepositAccountOnHoldTransactionType { return this.code; } - public static DepositAccountOnHoldTransactionType fromInt(final Integer transactionType) { - - if (transactionType == null) { - return DepositAccountOnHoldTransactionType.INVALID; + public static DepositAccountOnHoldTransactionType fromInt(final Integer v) { + if (v == null) { + return INVALID; } - DepositAccountOnHoldTransactionType savingsAccountTransactionType = DepositAccountOnHoldTransactionType.INVALID; - switch (transactionType) { + switch (v) { case 1: - savingsAccountTransactionType = DepositAccountOnHoldTransactionType.HOLD; - break; + return HOLD; case 2: - savingsAccountTransactionType = DepositAccountOnHoldTransactionType.RELEASE; - break; - + return RELEASE; + default: + return INVALID; } - return savingsAccountTransactionType; } + // TODO: why not just use the enum values... just more boilerplate code here!! public boolean isHold() { - return this.value.equals(DepositAccountOnHoldTransactionType.HOLD.getValue()); + return this.equals(HOLD); } + // TODO: why not just use the enum values... just more boilerplate code here!! public boolean isRelease() { - return this.value.equals(DepositAccountOnHoldTransactionType.RELEASE.getValue()); + return this.equals(RELEASE); } - } diff --git a/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/DepositAccountType.java b/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/DepositAccountType.java index f9b3178b6..ca60bb51b 100644 --- a/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/DepositAccountType.java +++ b/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/DepositAccountType.java @@ -48,44 +48,48 @@ public enum DepositAccountType { return this.code; } - public static DepositAccountType fromInt(final Integer transactionType) { - - if (transactionType == null) { - return DepositAccountType.INVALID; + public static DepositAccountType fromInt(final Integer v) { + if (v == null) { + return INVALID; } - DepositAccountType depositAccountType = DepositAccountType.INVALID; - switch (transactionType) { + switch (v) { case 100: - depositAccountType = DepositAccountType.SAVINGS_DEPOSIT; - break; + return SAVINGS_DEPOSIT; case 200: - depositAccountType = DepositAccountType.FIXED_DEPOSIT; - break; + return FIXED_DEPOSIT; case 300: - depositAccountType = DepositAccountType.RECURRING_DEPOSIT; - break; + return RECURRING_DEPOSIT; case 400: - depositAccountType = DepositAccountType.CURRENT_DEPOSIT; - break; + return CURRENT_DEPOSIT; + default: + return INVALID; } - return depositAccountType; } + // TODO: why not just use the enum values... just more boilerplate code here!! public boolean isSavingsDeposit() { - return this.value.equals(DepositAccountType.SAVINGS_DEPOSIT.getValue()); + return this.equals(SAVINGS_DEPOSIT); } + // TODO: why not just use the enum values... just more boilerplate code here!! public boolean isFixedDeposit() { - return this.value.equals(DepositAccountType.FIXED_DEPOSIT.getValue()); + return this.equals(FIXED_DEPOSIT); } + // TODO: why not just use the enum values... just more boilerplate code here!! public boolean isRecurringDeposit() { - return this.value.equals(DepositAccountType.RECURRING_DEPOSIT.getValue()); + return this.equals(RECURRING_DEPOSIT); } + // TODO: why not just use the enum values... just more boilerplate code here!! public boolean isCurrentDeposit() { - return this.value.equals(DepositAccountType.CURRENT_DEPOSIT.getValue()); + return this.equals(CURRENT_DEPOSIT); + } + + // TODO: why not just use the enum values... just more boilerplate code here!! + public boolean isInvalid() { + return this.equals(INVALID); } @Override @@ -94,28 +98,15 @@ public enum DepositAccountType { } public String resourceName() { - - String resourceName; - switch (this) { case FIXED_DEPOSIT: - resourceName = DepositsApiConstants.FIXED_DEPOSIT_ACCOUNT_RESOURCE_NAME; - break; + return DepositsApiConstants.FIXED_DEPOSIT_ACCOUNT_RESOURCE_NAME; case RECURRING_DEPOSIT: - resourceName = DepositsApiConstants.RECURRING_DEPOSIT_ACCOUNT_RESOURCE_NAME; - break; + return DepositsApiConstants.RECURRING_DEPOSIT_ACCOUNT_RESOURCE_NAME; case SAVINGS_DEPOSIT: - resourceName = DepositsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME; - break; + return DepositsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME; default: - resourceName = "INVALID"; - break; + return "INVALID"; } - - return resourceName; - } - - public boolean isInvalid() { - return this.value.equals(DepositAccountType.INVALID.value); } } diff --git a/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/PreClosurePenalInterestOnType.java b/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/PreClosurePenalInterestOnType.java index 8bd52c853..f66656e38 100644 --- a/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/PreClosurePenalInterestOnType.java +++ b/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/PreClosurePenalInterestOnType.java @@ -18,8 +18,7 @@ */ package org.apache.fineract.portfolio.savings; -import java.util.ArrayList; -import java.util.List; +import java.util.Arrays; /** * An enumeration of supported calendar periods used in savings. @@ -45,41 +44,38 @@ public enum PreClosurePenalInterestOnType { return this.code; } - public static PreClosurePenalInterestOnType fromInt(final Integer type) { - PreClosurePenalInterestOnType penalInterestType = PreClosurePenalInterestOnType.INVALID; - if (type != null) { - switch (type) { - case 1: - penalInterestType = PreClosurePenalInterestOnType.WHOLE_TERM; - break; - case 2: - penalInterestType = PreClosurePenalInterestOnType.TILL_PREMATURE_WITHDRAWAL; - break; - } + public static PreClosurePenalInterestOnType fromInt(final Integer v) { + if (v == null) { + return INVALID; + } + + switch (v) { + case 1: + return WHOLE_TERM; + case 2: + return TILL_PREMATURE_WITHDRAWAL; + default: + return INVALID; } - return penalInterestType; } + // TODO: do we really need this?!? public static Object[] integerValues() { - final List values = new ArrayList<>(); - for (final PreClosurePenalInterestOnType enumType : values()) { - if (enumType.getValue() > 0) { - values.add(enumType.getValue()); - } - } - - return values.toArray(); + return Arrays.stream(values()).filter(value -> !INVALID.equals(value)).map(value -> value.value).toList().toArray(); } + // TODO: why not just use the enum values... just more boilerplate code here!! public boolean isInvalid() { - return this.value.equals(PreClosurePenalInterestOnType.INVALID.value); + return this.equals(INVALID); } + // TODO: why not just use the enum values... just more boilerplate code here!! public boolean isWholeTerm() { - return this.value.equals(PreClosurePenalInterestOnType.WHOLE_TERM.getValue()); + return this.equals(WHOLE_TERM); } + // TODO: why not just use the enum values... just more boilerplate code here!! public boolean isTillPrematureWithdrawal() { - return this.value.equals(PreClosurePenalInterestOnType.TILL_PREMATURE_WITHDRAWAL.getValue()); + return this.equals(TILL_PREMATURE_WITHDRAWAL); } } diff --git a/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/RecurringDepositType.java b/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/RecurringDepositType.java index 1462121f0..2994b0711 100644 --- a/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/RecurringDepositType.java +++ b/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/RecurringDepositType.java @@ -18,8 +18,7 @@ */ package org.apache.fineract.portfolio.savings; -import java.util.ArrayList; -import java.util.List; +import java.util.Arrays; /** * An enumeration of supported calendar periods used in savings. @@ -45,32 +44,27 @@ public enum RecurringDepositType { return this.code; } - public static RecurringDepositType fromInt(final Integer type) { - RecurringDepositType rdType = RecurringDepositType.INVALID; - if (type != null) { - switch (type) { - case 1: - rdType = RecurringDepositType.VOLUNTARY; - break; - case 2: - rdType = RecurringDepositType.MANDATORY; - break; - } + public static RecurringDepositType fromInt(final Integer v) { + if (v == null) { + return INVALID; + } + + switch (v) { + case 1: + return VOLUNTARY; + case 2: + return MANDATORY; + default: + return INVALID; } - return rdType; } + // TODO: do we really need this?!? public static Object[] integerValues() { - final List values = new ArrayList<>(); - for (final RecurringDepositType enumType : values()) { - if (enumType.getValue() > 0) { - values.add(enumType.getValue()); - } - } - - return values.toArray(); + return Arrays.stream(values()).filter(value -> !INVALID.equals(value)).map(value -> value.value).toList().toArray(); } + // TODO: why not just use the enum values... just more boilerplate code here!! public boolean isInvalid() { return this.value.equals(RecurringDepositType.INVALID.value); } diff --git a/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/SavingsAccountTransactionType.java b/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/SavingsAccountTransactionType.java index 48f5e00e6..639806c23 100644 --- a/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/SavingsAccountTransactionType.java +++ b/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/SavingsAccountTransactionType.java @@ -51,9 +51,7 @@ public enum SavingsAccountTransactionType { AMOUNT_HOLD(20, "savingsAccountTransactionType.onHold", TransactionEntryType.DEBIT), // AMOUNT_RELEASE(21, "savingsAccountTransactionType.release", TransactionEntryType.CREDIT); // - public static final SavingsAccountTransactionType[] VALUES = values(); - - private static final Map BY_ID = Arrays.stream(VALUES) + private static final Map BY_ID = Arrays.stream(values()) .collect(Collectors.toMap(SavingsAccountTransactionType::getValue, v -> v)); private final int value; @@ -195,6 +193,6 @@ public enum SavingsAccountTransactionType { @NotNull public static List getFiltered(Predicate filter) { - return Arrays.stream(VALUES).filter(filter).toList(); + return Arrays.stream(values()).filter(filter).toList(); } } diff --git a/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/SavingsCompoundingInterestPeriodType.java b/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/SavingsCompoundingInterestPeriodType.java index ba4b61296..3a326cd72 100644 --- a/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/SavingsCompoundingInterestPeriodType.java +++ b/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/SavingsCompoundingInterestPeriodType.java @@ -18,8 +18,7 @@ */ package org.apache.fineract.portfolio.savings; -import java.util.ArrayList; -import java.util.List; +import java.util.Arrays; /** *

@@ -28,18 +27,15 @@ import java.util.List; */ public enum SavingsCompoundingInterestPeriodType { - INVALID(0, "savingsCompoundingInterestPeriodType.invalid"), // - DAILY(1, "savingsCompoundingInterestPeriodType.daily"), // - // WEEKLY(2, "savingsCompoundingInterestPeriodType.weekly"), // - // BIWEEKLY(3, "savingsCompoundingInterestPeriodType.biweekly"), // + INVALID(0, "savingsCompoundingInterestPeriodType.invalid"), DAILY(1, "savingsCompoundingInterestPeriodType.daily"), + // WEEKLY(2, "savingsCompoundingInterestPeriodType.weekly"), + // BIWEEKLY(3, "savingsCompoundingInterestPeriodType.biweekly"), MONTHLY(4, "savingsCompoundingInterestPeriodType.monthly"), - QUATERLY(5, "savingsCompoundingInterestPeriodType.quarterly"), // - BI_ANNUAL(6, "savingsCompoundingInterestPeriodType.biannual"), // - ANNUAL(7, "savingsCompoundingInterestPeriodType.annual"); // + QUATERLY(5, "savingsCompoundingInterestPeriodType.quarterly"), BI_ANNUAL(6, "savingsCompoundingInterestPeriodType.biannual"), ANNUAL(7, + "savingsCompoundingInterestPeriodType.annual"); - // NO_COMPOUNDING_SIMPLE_INTEREST(8, - // "savingsCompoundingInterestPeriodType.nocompounding"); + // NO_COMPOUNDING_SIMPLE_INTEREST(8, "savingsCompoundingInterestPeriodType.nocompounding"); private final Integer value; private final String code; @@ -57,50 +53,35 @@ public enum SavingsCompoundingInterestPeriodType { return this.code; } + // TODO: do we really need this?!? public static Object[] integerValues() { - final List values = new ArrayList<>(); - for (final SavingsCompoundingInterestPeriodType enumType : values()) { - if (enumType.getValue() > 0) { - values.add(enumType.getValue()); - } - } - - return values.toArray(); + return Arrays.stream(values()).filter(value -> !INVALID.equals(value)).map(value -> value.value).toList().toArray(); } - public static SavingsCompoundingInterestPeriodType fromInt(final Integer type) { - SavingsCompoundingInterestPeriodType repaymentFrequencyType = SavingsCompoundingInterestPeriodType.INVALID; - if (type != null) { - switch (type) { - case 1: - repaymentFrequencyType = SavingsCompoundingInterestPeriodType.DAILY; - break; - case 2: - // repaymentFrequencyType = - // SavingsCompoundingInterestPeriodType.WEEKLY; - break; - case 3: - // repaymentFrequencyType = - // SavingsCompoundingInterestPeriodType.BIWEEKLY; - break; - case 4: - repaymentFrequencyType = SavingsCompoundingInterestPeriodType.MONTHLY; - break; - case 5: - repaymentFrequencyType = SavingsCompoundingInterestPeriodType.QUATERLY; - break; - case 6: - repaymentFrequencyType = SavingsCompoundingInterestPeriodType.BI_ANNUAL; - break; - case 7: - repaymentFrequencyType = SavingsCompoundingInterestPeriodType.ANNUAL; - break; - case 8: - // repaymentFrequencyType = - // SavingsCompoundingInterestPeriodType.NO_COMPOUNDING_SIMPLE_INTEREST; - break; - } + public static SavingsCompoundingInterestPeriodType fromInt(final Integer v) { + if (v == null) { + return INVALID; + } + + switch (v) { + case 1: + return DAILY; + // case 2: + // return WEEKLY; + // case 3: + // return BIWEEKLY; + case 4: + return MONTHLY; + case 5: + return QUATERLY; + case 6: + return BI_ANNUAL; + case 7: + return ANNUAL; + // case 8: + // return NO_COMPOUNDING_SIMPLE_INTEREST; + default: + return INVALID; } - return repaymentFrequencyType; } } diff --git a/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/SavingsInterestCalculationDaysInYearType.java b/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/SavingsInterestCalculationDaysInYearType.java index 616f017ab..e495b7fbd 100644 --- a/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/SavingsInterestCalculationDaysInYearType.java +++ b/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/SavingsInterestCalculationDaysInYearType.java @@ -18,8 +18,7 @@ */ package org.apache.fineract.portfolio.savings; -import java.util.ArrayList; -import java.util.List; +import java.util.Arrays; /** * @@ -51,29 +50,23 @@ public enum SavingsInterestCalculationDaysInYearType { return this.code; } + // TODO: do we really need this?!? public static Object[] integerValues() { - final List values = new ArrayList<>(); - for (final SavingsInterestCalculationDaysInYearType enumType : values()) { - if (enumType.getValue() > 0) { - values.add(enumType.getValue()); - } - } - - return values.toArray(); + return Arrays.stream(values()).filter(value -> !INVALID.equals(value)).map(value -> value.value).toList().toArray(); } - public static SavingsInterestCalculationDaysInYearType fromInt(final Integer type) { - SavingsInterestCalculationDaysInYearType repaymentFrequencyType = SavingsInterestCalculationDaysInYearType.INVALID; - if (type != null) { - switch (type) { - case 360: - repaymentFrequencyType = SavingsInterestCalculationDaysInYearType.DAYS_360; - break; - case 365: - repaymentFrequencyType = SavingsInterestCalculationDaysInYearType.DAYS_365; - break; - } + public static SavingsInterestCalculationDaysInYearType fromInt(final Integer v) { + if (v == null) { + return INVALID; + } + + switch (v) { + case 360: + return DAYS_360; + case 365: + return DAYS_365; + default: + return INVALID; } - return repaymentFrequencyType; } } diff --git a/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/SavingsInterestCalculationType.java b/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/SavingsInterestCalculationType.java index 72701c72f..c3f63ddfb 100644 --- a/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/SavingsInterestCalculationType.java +++ b/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/SavingsInterestCalculationType.java @@ -18,8 +18,7 @@ */ package org.apache.fineract.portfolio.savings; -import java.util.ArrayList; -import java.util.List; +import java.util.Arrays; /** * @@ -64,29 +63,23 @@ public enum SavingsInterestCalculationType { return this.code; } + // TODO: do we really need this?!? public static Object[] integerValues() { - final List values = new ArrayList<>(); - for (final SavingsInterestCalculationType enumType : values()) { - if (enumType.getValue() > 0) { - values.add(enumType.getValue()); - } - } - - return values.toArray(); + return Arrays.stream(values()).filter(value -> !INVALID.equals(value)).map(value -> value.value).toList().toArray(); } - public static SavingsInterestCalculationType fromInt(final Integer type) { - SavingsInterestCalculationType repaymentFrequencyType = SavingsInterestCalculationType.INVALID; - if (type != null) { - switch (type) { - case 1: - repaymentFrequencyType = SavingsInterestCalculationType.DAILY_BALANCE; - break; - case 2: - repaymentFrequencyType = SavingsInterestCalculationType.AVERAGE_DAILY_BALANCE; - break; - } + public static SavingsInterestCalculationType fromInt(final Integer v) { + if (v == null) { + return INVALID; + } + + switch (v) { + case 1: + return DAILY_BALANCE; + case 2: + return AVERAGE_DAILY_BALANCE; + default: + return INVALID; } - return repaymentFrequencyType; } } diff --git a/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/SavingsPeriodFrequencyType.java b/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/SavingsPeriodFrequencyType.java index 0fb4ccbc9..cfebadce2 100644 --- a/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/SavingsPeriodFrequencyType.java +++ b/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/SavingsPeriodFrequencyType.java @@ -18,8 +18,7 @@ */ package org.apache.fineract.portfolio.savings; -import java.util.ArrayList; -import java.util.List; +import java.util.Arrays; /** * An enumeration of supported calendar periods used in savings. @@ -48,39 +47,32 @@ public enum SavingsPeriodFrequencyType { return this.code; } - public static SavingsPeriodFrequencyType fromInt(final Integer type) { - SavingsPeriodFrequencyType repaymentFrequencyType = SavingsPeriodFrequencyType.INVALID; - if (type != null) { - switch (type) { - case 0: - repaymentFrequencyType = SavingsPeriodFrequencyType.DAYS; - break; - case 1: - repaymentFrequencyType = SavingsPeriodFrequencyType.WEEKS; - break; - case 2: - repaymentFrequencyType = SavingsPeriodFrequencyType.MONTHS; - break; - case 3: - repaymentFrequencyType = SavingsPeriodFrequencyType.YEARS; - break; - } + public static SavingsPeriodFrequencyType fromInt(final Integer v) { + if (v == null) { + return INVALID; + } + + switch (v) { + case 0: + return DAYS; + case 1: + return WEEKS; + case 2: + return MONTHS; + case 3: + return YEARS; + default: + return INVALID; } - return repaymentFrequencyType; } + // TODO: why not just use the enum values... just more boilerplate code here!! public boolean isInvalid() { - return this.value.equals(SavingsPeriodFrequencyType.INVALID.value); + return this.equals(INVALID); } + // TODO: do we really need this?!? public static Object[] integerValues() { - final List values = new ArrayList<>(); - for (final SavingsPeriodFrequencyType enumType : values()) { - if (!enumType.isInvalid()) { - values.add(enumType.getValue()); - } - } - - return values.toArray(); + return Arrays.stream(values()).filter(value -> !INVALID.equals(value)).map(value -> value.value).toList().toArray(); } } diff --git a/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/SavingsPostingInterestPeriodType.java b/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/SavingsPostingInterestPeriodType.java index aefdb5f08..4da0987a6 100644 --- a/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/SavingsPostingInterestPeriodType.java +++ b/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/SavingsPostingInterestPeriodType.java @@ -18,8 +18,7 @@ */ package org.apache.fineract.portfolio.savings; -import java.util.ArrayList; -import java.util.List; +import java.util.Arrays; /** * The interest posting period is the span of time at the end of which savings earned but not yet credited/posted in a @@ -49,38 +48,29 @@ public enum SavingsPostingInterestPeriodType { return this.code; } + // TODO: do we really need this?!? public static Object[] integerValues() { - final List values = new ArrayList<>(); - for (final SavingsPostingInterestPeriodType enumType : values()) { - if (enumType.getValue() > 0) { - values.add(enumType.getValue()); - } - } - - return values.toArray(); + return Arrays.stream(values()).filter(value -> !INVALID.equals(value)).map(value -> value.value).toList().toArray(); } - public static SavingsPostingInterestPeriodType fromInt(final Integer type) { - SavingsPostingInterestPeriodType repaymentFrequencyType = SavingsPostingInterestPeriodType.INVALID; - if (type != null) { - switch (type) { - case 1: - repaymentFrequencyType = SavingsPostingInterestPeriodType.DAILY; - break; - case 4: - repaymentFrequencyType = SavingsPostingInterestPeriodType.MONTHLY; - break; - case 5: - repaymentFrequencyType = SavingsPostingInterestPeriodType.QUATERLY; - break; - case 6: - repaymentFrequencyType = SavingsPostingInterestPeriodType.BIANNUAL; - break; - case 7: - repaymentFrequencyType = SavingsPostingInterestPeriodType.ANNUAL; - break; - } + public static SavingsPostingInterestPeriodType fromInt(final Integer v) { + if (v == null) { + return INVALID; + } + + switch (v) { + case 1: + return DAILY; + case 4: + return MONTHLY; + case 5: + return QUATERLY; + case 6: + return BIANNUAL; + case 7: + return ANNUAL; + default: + return INVALID; } - return repaymentFrequencyType; } } diff --git a/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/SavingsWithdrawalFeesType.java b/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/SavingsWithdrawalFeesType.java index e8b1f8018..7aaaed0d8 100644 --- a/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/SavingsWithdrawalFeesType.java +++ b/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/SavingsWithdrawalFeesType.java @@ -18,8 +18,7 @@ */ package org.apache.fineract.portfolio.savings; -import java.util.ArrayList; -import java.util.List; +import java.util.Arrays; public enum SavingsWithdrawalFeesType { @@ -43,28 +42,23 @@ public enum SavingsWithdrawalFeesType { return this.code; } + // TODO: do we really need this?!? public static Object[] integerValues() { - final List values = new ArrayList<>(); - for (final SavingsWithdrawalFeesType enumType : values()) { - if (enumType.getValue() > 0) { - values.add(enumType.getValue()); - } - } - - return values.toArray(); + return Arrays.stream(values()).filter(value -> !INVALID.equals(value)).map(value -> value.value).toList().toArray(); } - public static SavingsWithdrawalFeesType fromInt(final Integer type) { + public static SavingsWithdrawalFeesType fromInt(final Integer v) { + if (v == null) { + return INVALID; + } - SavingsWithdrawalFeesType withdrawalFeeType = SavingsWithdrawalFeesType.INVALID; - switch (type) { + switch (v) { case 1: - withdrawalFeeType = FLAT; - break; + return FLAT; case 2: - withdrawalFeeType = PERCENT_OF_AMOUNT; - break; + return PERCENT_OF_AMOUNT; + default: + return INVALID; } - return withdrawalFeeType; } } diff --git a/fineract-doc/.asciidoctorconfig b/fineract-doc/.asciidoctorconfig index b8b621676..c6fcc35fe 100644 --- a/fineract-doc/.asciidoctorconfig +++ b/fineract-doc/.asciidoctorconfig @@ -1,5 +1,5 @@ -:years: 2015-2022 -:revnumber: 1.8.0 +:years: 2015-2024 +:revnumber: 1.9.0-xxxx :draft: true :rootdir: {asciidoctorconfigdir}/.. :generated: {asciidoctorconfigdir}/build/generated/asciidoc diff --git a/fineract-doc/build.gradle b/fineract-doc/build.gradle index d9464d20b..7f1c6bb67 100644 --- a/fineract-doc/build.gradle +++ b/fineract-doc/build.gradle @@ -30,7 +30,7 @@ asciidoctorj { generated: "${buildDir}/generated/asciidoc", imagesdir: "${projectDir}/src/docs/en/images", diagramsdir: "${projectDir}/src/docs/en/diagrams", - years: '2015-2022', + years: '2015-2024', revnumber: "${project.version}".toString(), rootdir: "${rootDir}".toString(), baseurl: 'fineract.apache.org', diff --git a/fineract-doc/src/docs/en/config.adoc b/fineract-doc/src/docs/en/config.adoc index dd47f4ec7..fe6046958 100644 --- a/fineract-doc/src/docs/en/config.adoc +++ b/fineract-doc/src/docs/en/config.adoc @@ -14,7 +14,7 @@ :source-highlighter: coderay :experimental: :source-language: java -:years: 2015-2022 +:years: 2015-2024 :lang: en :encoding: utf-8 :linkattrs: diff --git a/fineract-investor/dependencies.gradle b/fineract-investor/dependencies.gradle index 44a84d1d9..943673f45 100644 --- a/fineract-investor/dependencies.gradle +++ b/fineract-investor/dependencies.gradle @@ -52,7 +52,7 @@ dependencies { 'org.springdoc:springdoc-openapi-starter-webmvc-ui', 'org.mapstruct:mapstruct', - 'io.github.resilience4j:resilience4j-spring-boot2', + 'io.github.resilience4j:resilience4j-spring-boot3', ) compileOnly 'org.projectlombok:lombok' annotationProcessor 'org.projectlombok:lombok' diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/service/ExternalAssetOwnerJournalEntryServiceImpl.java b/fineract-investor/src/main/java/org/apache/fineract/investor/service/ExternalAssetOwnerJournalEntryServiceImpl.java index dcd41fcb2..186bb64c7 100644 --- a/fineract-investor/src/main/java/org/apache/fineract/investor/service/ExternalAssetOwnerJournalEntryServiceImpl.java +++ b/fineract-investor/src/main/java/org/apache/fineract/investor/service/ExternalAssetOwnerJournalEntryServiceImpl.java @@ -22,7 +22,6 @@ import jakarta.annotation.PostConstruct; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.fineract.accounting.journalentry.domain.JournalEntry; -import org.apache.fineract.infrastructure.event.business.BusinessEventListener; import org.apache.fineract.infrastructure.event.business.domain.journalentry.LoanJournalEntryCreatedBusinessEvent; import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService; import org.apache.fineract.investor.config.InvestorModuleIsEnabledCondition; @@ -46,26 +45,17 @@ public class ExternalAssetOwnerJournalEntryServiceImpl implements ExternalAssetO @PostConstruct public void addListeners() { - businessEventNotifierService.addPostBusinessEventListener(LoanJournalEntryCreatedBusinessEvent.class, - new HandleLoanJournalEntryCreatedBusinessEvent()); - } - - private final class HandleLoanJournalEntryCreatedBusinessEvent implements BusinessEventListener { - - @Override - public void onBusinessEvent(LoanJournalEntryCreatedBusinessEvent event) { + businessEventNotifierService.addPostBusinessEventListener(LoanJournalEntryCreatedBusinessEvent.class, event -> { JournalEntry journalEntry = event.get(); - createMapping(journalEntry); - } - private void createMapping(JournalEntry journalEntry) { Long loanId = loanTransactionRepository.findLoanIdById(journalEntry.getLoanTransactionId()).orElseThrow(); + externalAssetOwnerTransferLoanMappingRepository.findByLoanId(loanId).ifPresent(transferLoanMapping -> { ExternalAssetOwnerJournalEntryMapping mapping = new ExternalAssetOwnerJournalEntryMapping(); mapping.setJournalEntry(journalEntry); mapping.setOwner(transferLoanMapping.getOwnerTransfer().getOwner()); externalAssetOwnerJournalEntryMappingRepository.saveAndFlush(mapping); }); - } + }); } } diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/service/ExternalAssetOwnerLoanStatusChangePlatformServiceImpl.java b/fineract-investor/src/main/java/org/apache/fineract/investor/service/ExternalAssetOwnerLoanStatusChangePlatformServiceImpl.java index e1855f0b1..efe3d7214 100644 --- a/fineract-investor/src/main/java/org/apache/fineract/investor/service/ExternalAssetOwnerLoanStatusChangePlatformServiceImpl.java +++ b/fineract-investor/src/main/java/org/apache/fineract/investor/service/ExternalAssetOwnerLoanStatusChangePlatformServiceImpl.java @@ -21,7 +21,6 @@ package org.apache.fineract.investor.service; import jakarta.annotation.PostConstruct; import lombok.RequiredArgsConstructor; import org.apache.fineract.infrastructure.configuration.service.ConfigurationReadPlatformService; -import org.apache.fineract.infrastructure.event.business.BusinessEventListener; import org.apache.fineract.infrastructure.event.business.domain.loan.LoanStatusChangedBusinessEvent; import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService; import org.apache.fineract.portfolio.loanaccount.domain.Loan; @@ -39,19 +38,12 @@ public class ExternalAssetOwnerLoanStatusChangePlatformServiceImpl implements Ex @PostConstruct public void addListeners() { - businessEventNotifierService.addPostBusinessEventListener(LoanStatusChangedBusinessEvent.class, - new ExternalAssetOwnerLoanStatusChangedListener()); - } - - private final class ExternalAssetOwnerLoanStatusChangedListener implements BusinessEventListener { - - @Override - public void onBusinessEvent(LoanStatusChangedBusinessEvent event) { + businessEventNotifierService.addPostBusinessEventListener(LoanStatusChangedBusinessEvent.class, event -> { final Loan loan = event.get(); if (configurationReadPlatformService.retrieveGlobalConfiguration(ASSET_EXTERNALIZATION_OF_NON_ACTIVE_LOANS).isEnabled() && (loan.isClosed() || loan.getStatus().isOverpaid())) { loanAccountOwnerTransferService.handleLoanClosedOrOverpaid(loan); } - } + }); } } diff --git a/fineract-loan/dependencies.gradle b/fineract-loan/dependencies.gradle index c6f4d7c1a..bd2a15867 100644 --- a/fineract-loan/dependencies.gradle +++ b/fineract-loan/dependencies.gradle @@ -47,7 +47,7 @@ dependencies { 'org.springdoc:springdoc-openapi-starter-webmvc-ui', 'org.mapstruct:mapstruct', - 'io.github.resilience4j:resilience4j-spring-boot2', + 'io.github.resilience4j:resilience4j-spring-boot3', 'org.apache.httpcomponents:httpcore', ) compileOnly 'org.projectlombok:lombok' diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/collateral/api/CollateralApiConstants.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/collateral/api/CollateralApiConstants.java index 597791b35..cc0d8b3ef 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/collateral/api/CollateralApiConstants.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/collateral/api/CollateralApiConstants.java @@ -18,8 +18,9 @@ */ package org.apache.fineract.portfolio.collateral.api; -import java.util.HashSet; +import java.util.Arrays; import java.util.Set; +import java.util.stream.Collectors; public final class CollateralApiConstants { @@ -43,16 +44,8 @@ public final class CollateralApiConstants { this.value = value; } - private static final Set values = new HashSet<>(); - - static { - for (final CollateralJSONinputParams type : CollateralJSONinputParams.values()) { - values.add(type.value); - } - } - public static Set getAllValues() { - return values; + return Arrays.stream(values()).map(CollateralJSONinputParams::getValue).collect(Collectors.toSet()); } @Override diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/command/LoanChargeCommand.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/command/LoanChargeCommand.java index 4b906bd0c..a135c5ab5 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/command/LoanChargeCommand.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/command/LoanChargeCommand.java @@ -18,6 +18,7 @@ */ package org.apache.fineract.portfolio.loanaccount.command; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.math.BigDecimal; import java.time.LocalDate; import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge; @@ -49,6 +50,7 @@ public class LoanChargeCommand implements Comparable { } @Override + @SuppressFBWarnings(value = "EQ_COMPARETO_USE_OBJECT_EQUALS", justification = "TODO: fix this! See: https://stackoverflow.com/questions/2609037/findbugs-how-to-solve-eq-compareto-use-object-equals") public int compareTo(final LoanChargeCommand o) { int comparison = this.chargeId.compareTo(o.chargeId); if (comparison == 0) { diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/AbstractLoanRepaymentScheduleTransactionProcessor.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/AbstractLoanRepaymentScheduleTransactionProcessor.java index 52ca276fe..c258ef1ee 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/AbstractLoanRepaymentScheduleTransactionProcessor.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/AbstractLoanRepaymentScheduleTransactionProcessor.java @@ -26,6 +26,7 @@ import java.util.Comparator; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.Set; import org.apache.fineract.infrastructure.core.service.DateUtils; @@ -688,7 +689,7 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen if (loanTransaction.isChargePayment()) { for (final LoanChargePaidBy chargePaidBy : chargesPaidBies) { LoanCharge loanCharge = chargePaidBy.getLoanCharge(); - if (loanCharge.getId().equals(unpaidCharge.getId())) { + if (loanCharge != null && Objects.equals(loanCharge.getId(), unpaidCharge.getId())) { chargePaidBy.setAmount(amountPaidTowardsCharge.getAmount()); } } diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/ChargeOrTransaction.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/ChargeOrTransaction.java index 5c5a4a043..4e69c90c3 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/ChargeOrTransaction.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/ChargeOrTransaction.java @@ -18,6 +18,7 @@ */ package org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.time.LocalDate; import java.time.OffsetDateTime; import java.util.Optional; @@ -81,6 +82,7 @@ public class ChargeOrTransaction implements Comparable { } @Override + @SuppressFBWarnings(value = "EQ_COMPARETO_USE_OBJECT_EQUALS", justification = "TODO: fix this! See: https://stackoverflow.com/questions/2609037/findbugs-how-to-solve-eq-compareto-use-object-equals") public int compareTo(@NotNull ChargeOrTransaction o) { int datePortion = this.getEffectiveDate().compareTo(o.getEffectiveDate()); if (datePortion == 0) { diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/HeavensFamilyLoanRepaymentScheduleTransactionProcessor.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/HeavensFamilyLoanRepaymentScheduleTransactionProcessor.java index 984609ec6..f9d065abe 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/HeavensFamilyLoanRepaymentScheduleTransactionProcessor.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/HeavensFamilyLoanRepaymentScheduleTransactionProcessor.java @@ -221,7 +221,6 @@ public class HeavensFamilyLoanRepaymentScheduleTransactionProcessor extends Abst List transactionMappings) { final LocalDate transactionDate = loanTransaction.getTransactionDate(); - final MonetaryCurrency currency = transactionAmountUnprocessed.getCurrency(); Money transactionAmountRemaining = transactionAmountUnprocessed; Money principalPortion = Money.zero(transactionAmountRemaining.getCurrency()); Money interestPortion = Money.zero(transactionAmountRemaining.getCurrency()); diff --git a/fineract-provider/build.gradle b/fineract-provider/build.gradle index c767aa1a3..18926a94a 100644 --- a/fineract-provider/build.gradle +++ b/fineract-provider/build.gradle @@ -336,6 +336,12 @@ cucumber { tags = 'not @ignore' main = 'io.cucumber.core.cli.Main' shorten = 'argfile' + plugin = [ + 'pretty', + 'html:build/reports/cucumber/report.html', + 'json:build/reports/cucumber/report.json', + 'junit:build/reports/cucumber/report.xml' + ] } tasks.jibDockerBuild.dependsOn(bootJar) diff --git a/fineract-provider/dependencies.gradle b/fineract-provider/dependencies.gradle index 60a5e7c82..75ba8b9d8 100644 --- a/fineract-provider/dependencies.gradle +++ b/fineract-provider/dependencies.gradle @@ -18,6 +18,12 @@ */ dependencies { + modules { + module("io.swagger.core.v3:swagger-annotations") { + replacedBy("io.swagger.core.v3:swagger-annotations-jakarta") + } + } + implementation(project(path: ':fineract-core')) implementation(project(path: ':fineract-investor')) implementation(project(path: ':fineract-loan')) @@ -96,14 +102,14 @@ dependencies { 'org.springdoc:springdoc-openapi-starter-webmvc-ui', 'org.mapstruct:mapstruct', - 'io.github.resilience4j:resilience4j-spring-boot2', + 'io.github.resilience4j:resilience4j-spring-boot3', ) - implementation ('software.amazon.msk:aws-msk-iam-auth:2.0.0') { + implementation ('software.amazon.msk:aws-msk-iam-auth:2.0.2') { exclude group: 'commons-logging' } - implementation 'io.swagger.core.v3:swagger-jaxrs2-jakarta:2.2.11' + implementation 'io.swagger.core.v3:swagger-jaxrs2-jakarta:2.2.19' implementation ('org.apache.commons:commons-email') { exclude group: 'com.sun.mail', module: 'javax.mail' @@ -122,7 +128,7 @@ dependencies { implementation ('jakarta.xml.bind:jakarta.xml.bind-api') { exclude group: 'jakarta.activation' } - implementation ('org.apache.activemq:activemq-client') { + implementation ('org.apache.activemq:activemq-client-jakarta') { exclude group: 'org.apache.geronimo.specs' exclude group: 'javax.annotation', module: 'javax.annotation-api' } diff --git a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/api/JournalEntriesApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/api/JournalEntriesApiResource.java index c107c8a60..48b655a25 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/api/JournalEntriesApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/api/JournalEntriesApiResource.java @@ -83,7 +83,7 @@ public class JournalEntriesApiResource { "entityType", "entityId", "createdByUserId", "createdDate", "submittedOnDate", "createdByUserName", "comments", "reversed", "referenceNumber", "currency", "transactionDetails")); - private final String resourceNameForPermission = "JOURNALENTRY"; + private static final String RESOURCE_NAME_FOR_PERMISSION = "JOURNALENTRY"; private final PlatformSecurityContext context; private final JournalEntryReadPlatformService journalEntryReadPlatformService; @@ -125,7 +125,7 @@ public class JournalEntriesApiResource { @QueryParam("runningBalance") @Parameter(description = "runningBalance") final boolean runningBalance, @QueryParam("transactionDetails") @Parameter(description = "transactionDetails") final boolean transactionDetails) { - this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermission); + this.context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSION); final DateFormat dateFormat = StringUtils.isBlank(rawDateFormat) ? null : new DateFormat(rawDateFormat); @@ -174,7 +174,7 @@ public class JournalEntriesApiResource { @QueryParam("runningBalance") @Parameter(description = "runningBalance") final boolean runningBalance, @QueryParam("transactionDetails") @Parameter(description = "transactionDetails") final boolean transactionDetails) { - this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermission); + this.context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSION); JournalEntryAssociationParametersData associationParametersData = new JournalEntryAssociationParametersData(transactionDetails, runningBalance); final JournalEntryData glJournalEntryData = this.journalEntryReadPlatformService.retrieveGLJournalEntryById(journalEntryId, @@ -260,7 +260,7 @@ public class JournalEntriesApiResource { public String retrieveOpeningBalance(@Context final UriInfo uriInfo, @QueryParam("officeId") final Long officeId, @QueryParam("currencyCode") final String currencyCode) { - this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermission); + this.context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSION); final OfficeOpeningBalancesData officeOpeningBalancesData = this.journalEntryReadPlatformService .retrieveOfficeOpeningBalances(officeId, currencyCode); final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); diff --git a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccrualBasedAccountingProcessorForLoan.java b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccrualBasedAccountingProcessorForLoan.java index 1272055ca..49aaf44a5 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccrualBasedAccountingProcessorForLoan.java +++ b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccrualBasedAccountingProcessorForLoan.java @@ -724,10 +724,6 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess populateCreditDebitMaps(loanProductId, overPaymentAmount, paymentTypeId, AccrualAccountsForLoan.OVERPAYMENT.getValue(), AccrualAccountsForLoan.GOODWILL_CREDIT.getValue(), accountMapForCredit, accountMapForDebit); - } else if (loanTransactionDTO.getTransactionType().isRepayment()) { - populateCreditDebitMaps(loanProductId, overPaymentAmount, paymentTypeId, AccrualAccountsForLoan.OVERPAYMENT.getValue(), - AccrualAccountsForLoan.FUND_SOURCE.getValue(), accountMapForCredit, accountMapForDebit); - } else { populateCreditDebitMaps(loanProductId, overPaymentAmount, paymentTypeId, AccrualAccountsForLoan.OVERPAYMENT.getValue(), AccrualAccountsForLoan.FUND_SOURCE.getValue(), accountMapForCredit, accountMapForDebit); diff --git a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/CashBasedAccountingProcessorForLoan.java b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/CashBasedAccountingProcessorForLoan.java index 6786c8a7f..88f5f39c5 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/CashBasedAccountingProcessorForLoan.java +++ b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/CashBasedAccountingProcessorForLoan.java @@ -701,10 +701,6 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF } else if (loanTransactionDTO.getTransactionType().isGoodwillCredit()) { populateCreditDebitMaps(loanProductId, overPaymentAmount, paymentTypeId, CashAccountsForLoan.OVERPAYMENT.getValue(), CashAccountsForLoan.GOODWILL_CREDIT.getValue(), accountMapForCredit, accountMapForDebit); - } else if (loanTransactionDTO.getTransactionType().isRepayment()) { - populateCreditDebitMaps(loanProductId, overPaymentAmount, paymentTypeId, CashAccountsForLoan.OVERPAYMENT.getValue(), - CashAccountsForLoan.FUND_SOURCE.getValue(), accountMapForCredit, accountMapForDebit); - } else { populateCreditDebitMaps(loanProductId, overPaymentAmount, paymentTypeId, CashAccountsForLoan.OVERPAYMENT.getValue(), CashAccountsForLoan.FUND_SOURCE.getValue(), accountMapForCredit, accountMapForDebit); diff --git a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/JournalEntryWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/JournalEntryWritePlatformServiceJpaRepositoryImpl.java index bfc192996..fa1d72737 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/JournalEntryWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/JournalEntryWritePlatformServiceJpaRepositoryImpl.java @@ -27,7 +27,6 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.Set; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; @@ -401,50 +400,46 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa } } - Set officeSet = officeMap.keySet(); Map liabilityMap = new HashMap<>(); Map expenseMap = new HashMap<>(); - for (OfficeCurrencyKey key : officeSet) { + for (Map.Entry> entry : officeMap.entrySet()) { liabilityMap.clear(); expenseMap.clear(); - List entries = officeMap.get(key); - for (LoanProductProvisioningEntry entry : entries) { - if (liabilityMap.containsKey(entry.getLiabilityAccount())) { - BigDecimal amount = liabilityMap.get(entry.getLiabilityAccount()); - amount = amount.add(entry.getReservedAmount()); - liabilityMap.put(entry.getLiabilityAccount(), amount); + for (LoanProductProvisioningEntry lppEntry : entry.getValue()) { + if (liabilityMap.containsKey(lppEntry.getLiabilityAccount())) { + BigDecimal amount = liabilityMap.get(lppEntry.getLiabilityAccount()); + amount = amount.add(lppEntry.getReservedAmount()); + liabilityMap.put(lppEntry.getLiabilityAccount(), amount); } else { - BigDecimal amount = BigDecimal.ZERO.add(entry.getReservedAmount()); - liabilityMap.put(entry.getLiabilityAccount(), amount); + BigDecimal amount = BigDecimal.ZERO.add(lppEntry.getReservedAmount()); + liabilityMap.put(lppEntry.getLiabilityAccount(), amount); } - if (expenseMap.containsKey(entry.getExpenseAccount())) { - BigDecimal amount = expenseMap.get(entry.getExpenseAccount()); - amount = amount.add(entry.getReservedAmount()); - expenseMap.put(entry.getExpenseAccount(), amount); + if (expenseMap.containsKey(lppEntry.getExpenseAccount())) { + BigDecimal amount = expenseMap.get(lppEntry.getExpenseAccount()); + amount = amount.add(lppEntry.getReservedAmount()); + expenseMap.put(lppEntry.getExpenseAccount(), amount); } else { - BigDecimal amount = BigDecimal.ZERO.add(entry.getReservedAmount()); - expenseMap.put(entry.getExpenseAccount(), amount); + BigDecimal amount = BigDecimal.ZERO.add(lppEntry.getReservedAmount()); + expenseMap.put(lppEntry.getExpenseAccount(), amount); } } - createJournalEntry(provisioningEntry.getCreatedDate(), provisioningEntry.getId(), key.office, key.currency, liabilityMap, - expenseMap); + createJournalEntry(provisioningEntry.getCreatedDate(), provisioningEntry.getId(), entry.getKey().office, + entry.getKey().currency, liabilityMap, expenseMap); } return "P" + provisioningEntry.getId(); } private void createJournalEntry(LocalDate transactionDate, Long entryId, Office office, String currencyCode, Map liabilityMap, Map expenseMap) { - Set liabilityAccounts = liabilityMap.keySet(); - for (GLAccount account : liabilityAccounts) { - this.helper.createProvisioningCreditJournalEntry(transactionDate, entryId, office, currencyCode, account, - liabilityMap.get(account)); + for (Map.Entry entry : liabilityMap.entrySet()) { + this.helper.createProvisioningCreditJournalEntry(transactionDate, entryId, office, currencyCode, entry.getKey(), + entry.getValue()); } - Set expenseAccounts = expenseMap.keySet(); - for (GLAccount account : expenseAccounts) { - this.helper.createProvisioningDebitJournalEntry(transactionDate, entryId, office, currencyCode, account, - expenseMap.get(account)); + for (Map.Entry entry : expenseMap.entrySet()) { + this.helper.createProvisioningDebitJournalEntry(transactionDate, entryId, office, currencyCode, entry.getKey(), + entry.getValue()); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/accounting/rule/api/AccountingRuleApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/accounting/rule/api/AccountingRuleApiResource.java index 114db8359..40e155e48 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/accounting/rule/api/AccountingRuleApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/accounting/rule/api/AccountingRuleApiResource.java @@ -86,7 +86,7 @@ public class AccountingRuleApiResource { "allowedCreditTagOptions", "allowedDebitTagOptions", "debitTags", "creditTags", "creditAccounts", "debitAccounts", "allowMultipleCreditEntries", "allowMultipleDebitEntries", "tag")); - private final String resourceNameForPermission = "ACCOUNTINGRULE"; + private static final String RESOURCE_NAME_FOR_PERMISSION = "ACCOUNTINGRULE"; private final AccountingRuleReadPlatformService accountingRuleReadPlatformService; private final GLAccountReadPlatformService accountReadPlatformService; @@ -107,7 +107,7 @@ public class AccountingRuleApiResource { @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = AccountingRuleApiResourceSwagger.GetAccountRulesTemplateResponse.class))) }) public String retrieveTemplate(@Context final UriInfo uriInfo) { - this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermission); + this.context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSION); AccountingRuleData accountingRuleData = null; accountingRuleData = handleTemplate(accountingRuleData); @@ -126,7 +126,7 @@ public class AccountingRuleApiResource { public String retrieveAllAccountingRules(@Context final UriInfo uriInfo) { final AppUser currentUser = this.context.authenticatedUser(); - currentUser.validateHasReadPermission(this.resourceNameForPermission); + currentUser.validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSION); final String hierarchy = currentUser.getOffice().getHierarchy(); final String hierarchySearchString = hierarchy + "%"; @@ -159,7 +159,7 @@ public class AccountingRuleApiResource { @PathParam("accountingRuleId") @Parameter(description = "accountingRuleId") final Long accountingRuleId, @Context final UriInfo uriInfo) { - this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermission); + this.context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSION); final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); AccountingRuleData accountingRuleData = this.accountingRuleReadPlatformService.retrieveAccountingRuleById(accountingRuleId); diff --git a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/GetDatatableEntryByQueryCommandStrategy.java b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/GetDatatableEntryByQueryCommandStrategy.java index 75e71808e..4bb42c1e8 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/GetDatatableEntryByQueryCommandStrategy.java +++ b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/GetDatatableEntryByQueryCommandStrategy.java @@ -23,6 +23,7 @@ import static org.apache.fineract.batch.command.CommandStrategyUtils.relativeUrl import jakarta.ws.rs.core.UriInfo; import java.util.Map; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.apache.fineract.batch.command.CommandStrategy; import org.apache.fineract.batch.command.CommandStrategyUtils; @@ -39,6 +40,7 @@ import org.springframework.stereotype.Component; * raised by {@link DatatablesApiResource} and map those errors to appropriate status codes in BatchResponse. */ @Component +@Slf4j @RequiredArgsConstructor public class GetDatatableEntryByQueryCommandStrategy implements CommandStrategy { @@ -81,6 +83,7 @@ public class GetDatatableEntryByQueryCommandStrategy implements CommandStrategy case "columnFilter" -> columnFilter = entry.getValue(); case "valueFilter" -> valueFilter = entry.getValue(); case "resultColumns" -> resultColumns = entry.getValue(); + default -> log.warn("Query parameter could not be mapped: {}", entry.getKey()); } } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/cob/listener/AbstractLoanItemListener.java b/fineract-provider/src/main/java/org/apache/fineract/cob/listener/AbstractLoanItemListener.java index d02179180..df2bc95a1 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/cob/listener/AbstractLoanItemListener.java +++ b/fineract-provider/src/main/java/org/apache/fineract/cob/listener/AbstractLoanItemListener.java @@ -68,9 +68,12 @@ public abstract class AbstractLoanItemListener { @OnReadError public void onReadError(Exception e) { - LoanReadException ee = (LoanReadException) e; - log.warn("Error was triggered during reading of Loan (id={}) due to: {}", ee.getId(), ThrowableSerialization.serialize(e)); - updateAccountLockWithError(List.of(ee.getId()), "Loan (id: %d) reading is failed", e); + if (e instanceof LoanReadException ee) { + log.warn("Error was triggered during reading of Loan (id={}) due to: {}", ee.getId(), ThrowableSerialization.serialize(e)); + updateAccountLockWithError(List.of(ee.getId()), "Loan (id: %d) reading is failed", e); + } else { + log.error("Could not handle read error", e); + } } @OnProcessError diff --git a/fineract-provider/src/main/java/org/apache/fineract/cob/service/LoanCOBCatchUpServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/cob/service/LoanCOBCatchUpServiceImpl.java index 07a427fc1..8643df3b6 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/cob/service/LoanCOBCatchUpServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/cob/service/LoanCOBCatchUpServiceImpl.java @@ -18,7 +18,6 @@ */ package org.apache.fineract.cob.service; -import com.google.gson.Gson; import java.time.LocalDate; import java.util.List; import lombok.RequiredArgsConstructor; @@ -30,11 +29,8 @@ import org.apache.fineract.cob.loan.LoanCOBConstant; import org.apache.fineract.cob.loan.RetrieveLoanIdService; import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType; import org.apache.fineract.infrastructure.core.domain.FineractContext; -import org.apache.fineract.infrastructure.core.serialization.GoogleGsonSerializerHelper; import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil; -import org.apache.fineract.infrastructure.jobs.domain.CustomJobParameterRepository; import org.apache.fineract.infrastructure.jobs.domain.JobExecutionRepository; -import org.springframework.batch.core.explore.JobExplorer; import org.springframework.context.annotation.Conditional; import org.springframework.stereotype.Service; @@ -45,12 +41,8 @@ public class LoanCOBCatchUpServiceImpl implements LoanCOBCatchUpService { private final AsyncLoanCOBExecutorService asyncLoanCOBExecutorService; private final JobExecutionRepository jobExecutionRepository; - private final JobExplorer jobExplorer; private final RetrieveLoanIdService retrieveLoanIdService; - private final LoanAccountLockService accountLockService; - private final CustomJobParameterRepository customJobParameterRepository; - protected Gson gson = GoogleGsonSerializerHelper.createSimpleGson(); @Override public void unlockHardLockedLoans() { diff --git a/fineract-provider/src/main/java/org/apache/fineract/commands/api/AuditsApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/commands/api/AuditsApiResource.java index 744b10010..43486506c 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/commands/api/AuditsApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/commands/api/AuditsApiResource.java @@ -105,7 +105,7 @@ public class AuditsApiResource { @QueryParam("orderBy") @Parameter(description = "orderBy") final String orderBy, @QueryParam("sortOrder") @Parameter(description = "sortOrder") final String sortOrder) { - this.context.authenticatedUser().validateHasReadPermission(this.RESOURCE_NAME_FOR_PERMISSIONS); + this.context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSIONS); final PaginationParameters parameters = PaginationParameters.instance(paged, offset, limit, orderBy, sortOrder); final SQLBuilder extraCriteria = getExtraCriteria(actionName, entityName, resourceId, makerId, makerDateTimeFrom, makerDateTimeTo, checkerId, checkerDateTimeFrom, checkerDateTimeTo, processingResult, officeId, groupId, clientId, loanId, savingsAccountId); @@ -135,7 +135,7 @@ public class AuditsApiResource { public String retrieveAuditEntry(@PathParam("auditId") @Parameter(description = "auditId") final Long auditId, @Context final UriInfo uriInfo) { - this.context.authenticatedUser().validateHasReadPermission(this.RESOURCE_NAME_FOR_PERMISSIONS); + this.context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSIONS); final AuditData auditEntry = this.auditReadPlatformService.retrieveAuditEntry(auditId); @@ -153,7 +153,7 @@ public class AuditsApiResource { @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = MakercheckersApiResourceSwagger.GetMakerCheckersSearchTemplateResponse.class))) }) public String retrieveAuditSearchTemplate(@Context final UriInfo uriInfo) { - this.context.authenticatedUser().validateHasReadPermission(this.RESOURCE_NAME_FOR_PERMISSIONS); + this.context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSIONS); final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/importhandler/ImportHandlerUtils.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/importhandler/ImportHandlerUtils.java index 07c720d20..9adaee5ae 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/importhandler/ImportHandlerUtils.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/importhandler/ImportHandlerUtils.java @@ -21,6 +21,8 @@ package org.apache.fineract.infrastructure.bulkimport.importhandler; import com.google.common.base.Splitter; import java.time.LocalDate; import java.util.List; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.apache.fineract.infrastructure.bulkimport.constants.TemplatePopulateImportConstants; import org.apache.fineract.infrastructure.core.data.ApiParameterError; import org.apache.fineract.infrastructure.core.data.EnumOptionData; @@ -40,6 +42,7 @@ import org.apache.poi.ss.usermodel.SheetVisibility; import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.ss.util.CellReference; +@Slf4j public final class ImportHandlerUtils { private ImportHandlerUtils() { @@ -73,20 +76,20 @@ public final class ImportHandlerUtils { FormulaEvaluator eval = row.getSheet().getWorkbook().getCreationHelper().createFormulaEvaluator(); if (c.getCellType() == CellType.FORMULA) { if (eval != null) { - CellValue val = null; + CellValue value; try { - val = eval.evaluate(c); - } catch (NullPointerException npe) { - return null; + value = eval.evaluate(c); + return ((Double) value.getNumberValue()).longValue(); + } catch (Exception e) { + log.error("Cell evaluation error: ", e); } - return ((Double) val.getNumberValue()).longValue(); } + return null; } else if (c.getCellType() == CellType.NUMERIC) { return ((Double) c.getNumericCellValue()).longValue(); } else { return Long.parseLong(row.getCell(colIndex).getStringCellValue()); } - return null; } public static String readAsString(int colIndex, Row row) { @@ -98,26 +101,20 @@ public final class ImportHandlerUtils { FormulaEvaluator eval = row.getSheet().getWorkbook().getCreationHelper().createFormulaEvaluator(); if (c.getCellType() == CellType.FORMULA) { if (eval != null) { - CellValue val = null; + CellValue value; try { - val = eval.evaluate(c); - } catch (NullPointerException npe) { - return null; - } + value = eval.evaluate(c); - String res = trimEmptyDecimalPortion(val.getStringValue()); - if (res != null) { - if (!res.equals("")) { + String res = trimEmptyDecimalPortion(value.getStringValue()); + + if (!StringUtils.isNotEmpty(res)) { return res.trim(); - } else { - return null; } - } else { - return null; + } catch (Exception e) { + log.error("Cell evaluation error: ", e); } - } else { - return null; } + return null; } else if (c.getCellType() == CellType.STRING) { String res = trimEmptyDecimalPortion(c.getStringCellValue().trim()); return res.trim(); @@ -156,13 +153,13 @@ public final class ImportHandlerUtils { FormulaEvaluator eval = row.getSheet().getWorkbook().getCreationHelper().createFormulaEvaluator(); if (c.getCellType() == CellType.FORMULA) { if (eval != null) { - CellValue val = null; + CellValue value; try { - val = eval.evaluate(c); - } catch (NullPointerException npe) { - return false; + value = eval.evaluate(c); + return value.getBooleanValue(); + } catch (Exception e) { + log.error("Cell evaluation error: ", e); } - return val.getBooleanValue(); } return false; } else if (c.getCellType() == CellType.BOOLEAN) { @@ -185,13 +182,13 @@ public final class ImportHandlerUtils { FormulaEvaluator eval = row.getSheet().getWorkbook().getCreationHelper().createFormulaEvaluator(); if (c.getCellType() == CellType.FORMULA) { if (eval != null) { - CellValue val = null; + CellValue value; try { - val = eval.evaluate(c); - } catch (NullPointerException npe) { - return null; + value = eval.evaluate(c); + return ((Double) value.getNumberValue()).intValue(); + } catch (Exception e) { + log.error("Cell evaluation error: ", e); } - return ((Double) val.getNumberValue()).intValue(); } return null; } else if (c.getCellType() == CellType.NUMERIC) { @@ -209,16 +206,15 @@ public final class ImportHandlerUtils { FormulaEvaluator eval = row.getSheet().getWorkbook().getCreationHelper().createFormulaEvaluator(); if (c.getCellType() == CellType.FORMULA) { if (eval != null) { - CellValue val = null; + CellValue value; try { - val = eval.evaluate(c); - } catch (NullPointerException npe) { - return 0.0; + value = eval.evaluate(c); + return value.getNumberValue(); + } catch (Exception e) { + log.error("Cell evaluation error: ", e); } - return val.getNumberValue(); - } else { - return 0.0; } + return 0.0; } else if (c.getCellType() == CellType.NUMERIC) { return row.getCell(colIndex).getNumericCellValue(); } else { diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/populator/CenterSheetPopulator.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/populator/CenterSheetPopulator.java index d4064072c..d3dad4e89 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/populator/CenterSheetPopulator.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/populator/CenterSheetPopulator.java @@ -58,7 +58,7 @@ public class CenterSheetPopulator extends AbstractWorkbookPopulator { } private void centerNameToCenterIdMap() { - centerNameToCenterId = new HashMap(); + centerNameToCenterId = new HashMap<>(); for (CenterData centerData : allCenters) { centerNameToCenterId.put(centerData.getName(), centerData.getId()); } @@ -68,12 +68,12 @@ public class CenterSheetPopulator extends AbstractWorkbookPopulator { int rowIndex = 1; int officeIndex = 0; int startIndex = 1; - officeNameToBeginEndIndexesOfCenters = new HashMap(); + officeNameToBeginEndIndexesOfCenters = new HashMap<>(); Row row = centerSheet.createRow(rowIndex); for (OfficeData office : offices) { startIndex = rowIndex + 1; writeString(OFFICE_NAME_COL, row, office.getName()); - ArrayList centersList = new ArrayList(); + ArrayList centersList; if (officeToCenters.containsKey(office.getName().trim().replaceAll("[ )(]", "_"))) { centersList = officeToCenters.get(office.getName().trim().replaceAll("[ )(]", "_")); diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/populator/SavingsAccountSheetPopulator.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/populator/SavingsAccountSheetPopulator.java index 133fd5082..f33bdc300 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/populator/SavingsAccountSheetPopulator.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/populator/SavingsAccountSheetPopulator.java @@ -19,9 +19,7 @@ package org.apache.fineract.infrastructure.bulkimport.populator; import java.util.List; -import java.util.Map; import org.apache.fineract.infrastructure.bulkimport.constants.TemplatePopulateImportConstants; -import org.apache.fineract.portfolio.client.data.ClientData; import org.apache.fineract.portfolio.savings.data.SavingsAccountData; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; @@ -30,8 +28,6 @@ import org.apache.poi.ss.usermodel.Workbook; public class SavingsAccountSheetPopulator extends AbstractWorkbookPopulator { private List savingsAccountDataList; - private Map> clientToSavingsMap; - private static final int SAVINGS_ACCOUNT_ID_COL = 0; private static final int SAVING_ACCOUNT_NO = 1; private static final int CURRENCY_COL = 2; diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/populator/comparator/LoanComparatorByStatusActive.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/populator/comparator/LoanComparatorByStatusActive.java index 5bfc7721c..4a29c916b 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/populator/comparator/LoanComparatorByStatusActive.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/populator/comparator/LoanComparatorByStatusActive.java @@ -18,6 +18,7 @@ */ package org.apache.fineract.infrastructure.bulkimport.populator.comparator; +import java.io.Serializable; import java.util.Comparator; import org.apache.fineract.portfolio.loanaccount.data.LoanAccountData; @@ -25,7 +26,7 @@ import org.apache.fineract.portfolio.loanaccount.data.LoanAccountData; * Sorting the loan values based on loan status giving priority to active loans */ -public class LoanComparatorByStatusActive implements Comparator { +public class LoanComparatorByStatusActive implements Comparator, Serializable { @Override public int compare(LoanAccountData o1, LoanAccountData o2) { diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/constants/CampaignType.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/constants/CampaignType.java index 13e765c68..fffe54ad2 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/constants/CampaignType.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/constants/CampaignType.java @@ -41,19 +41,20 @@ public enum CampaignType { } public static CampaignType fromInt(final Integer typeValue) { - CampaignType type = null; + if (typeValue == null) { + return INVALID; + } + switch (typeValue) { case 0: - type = INVALID; - break; + return INVALID; case 1: - type = SMS; - break; + return SMS; case 2: - type = NOTIFICATION; - break; + return NOTIFICATION; + default: + return INVALID; } - return type; } public static EnumOptionData campaignType(final Integer campaignTypeId) { @@ -61,28 +62,22 @@ public enum CampaignType { } public static EnumOptionData campaignType(final CampaignType campaignType) { - EnumOptionData optionData = new EnumOptionData(CampaignType.INVALID.getValue().longValue(), CampaignType.INVALID.getCode(), - "Invalid"); + EnumOptionData optionData = new EnumOptionData(INVALID.getValue().longValue(), INVALID.getCode(), "Invalid"); switch (campaignType) { case INVALID: - optionData = new EnumOptionData(CampaignType.INVALID.getValue().longValue(), CampaignType.INVALID.getCode(), "Invalid"); + optionData = new EnumOptionData(INVALID.getValue().longValue(), INVALID.getCode(), "Invalid"); break; case SMS: - optionData = new EnumOptionData(CampaignType.SMS.getValue().longValue(), CampaignType.SMS.getCode(), "SMS"); + optionData = new EnumOptionData(SMS.getValue().longValue(), SMS.getCode(), "SMS"); break; case NOTIFICATION: - optionData = new EnumOptionData(CampaignType.NOTIFICATION.getValue().longValue(), CampaignType.NOTIFICATION.getCode(), - "NOTIFICATION"); + optionData = new EnumOptionData(NOTIFICATION.getValue().longValue(), NOTIFICATION.getCode(), "NOTIFICATION"); break; } return optionData; } public boolean isSms() { - return this.value.equals(CampaignType.SMS.getValue()); - } - - public boolean isNotificaion() { - return this.value.equals(CampaignType.NOTIFICATION.getValue()); + return this.equals(SMS); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/email/service/EmailCampaignReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/email/service/EmailCampaignReadPlatformServiceImpl.java index 0ef6b2bd0..ce0aee75c 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/email/service/EmailCampaignReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/email/service/EmailCampaignReadPlatformServiceImpl.java @@ -30,7 +30,6 @@ import java.util.Map; import org.apache.fineract.infrastructure.campaigns.email.data.EmailBusinessRulesData; import org.apache.fineract.infrastructure.campaigns.email.data.EmailCampaignData; import org.apache.fineract.infrastructure.campaigns.email.data.EmailCampaignTimeLine; -import org.apache.fineract.infrastructure.campaigns.email.data.ScheduledEmailEnumerations; import org.apache.fineract.infrastructure.campaigns.email.domain.EmailCampaignStatus; import org.apache.fineract.infrastructure.campaigns.email.domain.EmailCampaignStatusEnumerations; import org.apache.fineract.infrastructure.campaigns.email.domain.EmailCampaignType; @@ -116,24 +115,7 @@ public class EmailCampaignReadPlatformServiceImpl implements EmailCampaignReadPl final String emailMessage = rs.getString("emailMessage"); final String emailAttachmentFileFormatString = rs.getString("emailAttachmentFileFormat"); final String stretchyReportParamMap = rs.getString("stretchyReportParamMap"); - EnumOptionData emailAttachmentFileFormat = null; - if (emailAttachmentFileFormatString != null) { - emailAttachmentFileFormat = ScheduledEmailEnumerations.emailAttachementFileFormat(emailAttachmentFileFormatString); - } final Long reportId = JdbcSupport.getLong(rs, "stretchyReportId"); - final String reportName = rs.getString("reportName"); - final String reportType = rs.getString("reportType"); - final String reportSubType = rs.getString("reportSubType"); - final String reportCategory = rs.getString("reportCategory"); - final String reportSql = rs.getString("reportSql"); - final String reportDescription = rs.getString("reportDescription"); - final boolean coreReport = rs.getBoolean("coreReport"); - final boolean useReport = rs.getBoolean("useReport"); - - /* - * final ReportData stretchyReport = new ReportData(reportId, reportName, reportType, reportSubType, - * reportCategory, reportDescription, reportSql, coreReport, useReport, null); - */ final Integer statusId = JdbcSupport.getInteger(rs, "statusEnum"); final EnumOptionData status = EmailCampaignStatusEnumerations.status(statusId); diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/email/service/EmailCampaignWritePlatformCommandHandlerImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/email/service/EmailCampaignWritePlatformCommandHandlerImpl.java index 3b206bc75..ba3e487a4 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/email/service/EmailCampaignWritePlatformCommandHandlerImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/email/service/EmailCampaignWritePlatformCommandHandlerImpl.java @@ -350,11 +350,11 @@ public class EmailCampaignWritePlatformCommandHandlerImpl implements EmailCampai throws IOException { final String reportType = "report"; - List> resultList = new ArrayList>(); + List> resultList; final GenericResultsetData results = this.readReportingService.retrieveGenericResultSetForSmsEmailCampaign(reportName, reportType, queryParams); final String response = this.genericDataService.generateJsonFromGenericResultsetData(results); - resultList = new ObjectMapper().readValue(response, new TypeReference>>() {}); + resultList = new ObjectMapper().readValue(response, new TypeReference<>() {}); // loop changes array date to string date for (Iterator> it = resultList.iterator(); it.hasNext();) { HashMap entry = it.next(); diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/email/service/EmailConfigurationWritePlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/email/service/EmailConfigurationWritePlatformServiceImpl.java index 21f7a6cf5..9409e9972 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/email/service/EmailConfigurationWritePlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/email/service/EmailConfigurationWritePlatformServiceImpl.java @@ -30,7 +30,6 @@ import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; -import org.apache.fineract.useradministration.domain.AppUser; import org.springframework.stereotype.Service; @Service @@ -43,8 +42,9 @@ public class EmailConfigurationWritePlatformServiceImpl implements EmailConfigur @Override public CommandProcessingResult update(final JsonCommand command) { - - final AppUser currentUser = this.context.authenticatedUser(); + // TODO: leaving function call for backward compatibility... but security configuration should be done somewhere + // else + this.context.authenticatedUser(); this.emailConfigurationValidator.validateUpdateConfiguration(command.json()); final String smtpUsername = command.stringValueOfParameterNamed("SMTP_USERNAME"); diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/jobs/executeemail/ExecuteEmailTasklet.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/jobs/executeemail/ExecuteEmailTasklet.java index 069afb9ca..90168797c 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/jobs/executeemail/ExecuteEmailTasklet.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/jobs/executeemail/ExecuteEmailTasklet.java @@ -193,6 +193,8 @@ public class ExecuteEmailTasklet implements Tasklet { case "environementUrl": actualParams.put(entry.getKey(), entry.getKey()); break; + default: + log.warn("Query parameter could not be mapped: {}", entry.getKey()); } } return actualParams; diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/constants/SmsCampaignStatus.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/constants/SmsCampaignStatus.java index 399e90ac6..5f02b2a8b 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/constants/SmsCampaignStatus.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/constants/SmsCampaignStatus.java @@ -34,20 +34,16 @@ public enum SmsCampaignStatus { } public static SmsCampaignStatus fromInt(final Integer statusValue) { - - SmsCampaignStatus enumeration = SmsCampaignStatus.INVALID; switch (statusValue) { case 100: - enumeration = SmsCampaignStatus.PENDING; - break; + return PENDING; case 300: - enumeration = SmsCampaignStatus.ACTIVE; - break; + return ACTIVE; case 600: - enumeration = SmsCampaignStatus.CLOSED; - break; + return CLOSED; + default: + return INVALID; } - return enumeration; } public Integer getValue() { @@ -58,15 +54,18 @@ public enum SmsCampaignStatus { return code; } + // TODO: why not just use the enum values... just more boilerplate code here!! public boolean isActive() { - return this.value.equals(SmsCampaignStatus.ACTIVE.getValue()); + return this.equals(ACTIVE); } + // TODO: why not just use the enum values... just more boilerplate code here!! public boolean isPending() { - return this.value.equals(SmsCampaignStatus.PENDING.getValue()); + return this.equals(PENDING); } + // TODO: why not just use the enum values... just more boilerplate code here!! public boolean isClosed() { - return this.value.equals(SmsCampaignStatus.CLOSED.getValue()); + return this.equals(CLOSED); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/constants/SmsCampaignTriggerType.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/constants/SmsCampaignTriggerType.java index 83349e9bb..7f4cdef79 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/constants/SmsCampaignTriggerType.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/constants/SmsCampaignTriggerType.java @@ -41,20 +41,21 @@ public enum SmsCampaignTriggerType { return code; } - public static SmsCampaignTriggerType fromInt(final Integer typeValue) { - SmsCampaignTriggerType type = null; - switch (typeValue) { + public static SmsCampaignTriggerType fromInt(final Integer v) { + if (v == null) { + return INVALID; + } + + switch (v) { case 1: - type = DIRECT; - break; + return DIRECT; case 2: - type = SCHEDULE; - break; + return SCHEDULE; case 3: - type = TRIGGERED; - break; + return TRIGGERED; + default: + return INVALID; } - return type; } public static EnumOptionData triggerType(final Integer triggerTypeId) { @@ -62,38 +63,32 @@ public enum SmsCampaignTriggerType { } public static EnumOptionData triggerType(final SmsCampaignTriggerType triggerType) { - EnumOptionData optionData = new EnumOptionData(SmsCampaignTriggerType.INVALID.getValue().longValue(), - SmsCampaignTriggerType.INVALID.getCode(), "Invalid"); switch (triggerType) { case INVALID: - optionData = new EnumOptionData(SmsCampaignTriggerType.INVALID.getValue().longValue(), - SmsCampaignTriggerType.INVALID.getCode(), "Invalid"); - break; + return new EnumOptionData(INVALID.getValue().longValue(), INVALID.getCode(), "Invalid"); case DIRECT: - optionData = new EnumOptionData(SmsCampaignTriggerType.DIRECT.getValue().longValue(), - SmsCampaignTriggerType.DIRECT.getCode(), "Direct"); - break; + return new EnumOptionData(DIRECT.getValue().longValue(), DIRECT.getCode(), "Direct"); case SCHEDULE: - optionData = new EnumOptionData(SmsCampaignTriggerType.SCHEDULE.getValue().longValue(), - SmsCampaignTriggerType.SCHEDULE.getCode(), "Schedule"); - break; + return new EnumOptionData(SCHEDULE.getValue().longValue(), SCHEDULE.getCode(), "Schedule"); case TRIGGERED: - optionData = new EnumOptionData(SmsCampaignTriggerType.TRIGGERED.getValue().longValue(), - SmsCampaignTriggerType.TRIGGERED.getCode(), "Triggered"); - break; + return new EnumOptionData(TRIGGERED.getValue().longValue(), TRIGGERED.getCode(), "Triggered"); + default: + return new EnumOptionData(INVALID.getValue().longValue(), INVALID.getCode(), "Invalid"); } - return optionData; } + // TODO: why not just use the enum values... just more boilerplate code here!! public boolean isDirect() { - return this.value.equals(SmsCampaignTriggerType.DIRECT.getValue()); + return this.equals(DIRECT); } + // TODO: why not just use the enum values... just more boilerplate code here!! public boolean isSchedule() { - return this.value.equals(SmsCampaignTriggerType.SCHEDULE.getValue()); + return this.equals(SCHEDULE); } + // TODO: why not just use the enum values... just more boilerplate code here!! public boolean isTriggered() { - return this.value.equals(SmsCampaignTriggerType.TRIGGERED.getValue()); + return this.equals(TRIGGERED); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/service/SmsCampaignDomainServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/service/SmsCampaignDomainServiceImpl.java index 62debdffe..2cdf3d265 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/service/SmsCampaignDomainServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/service/SmsCampaignDomainServiceImpl.java @@ -183,18 +183,18 @@ public class SmsCampaignDomainServiceImpl implements SmsCampaignDomainService { }); - if (groupClients.size() > 0) { + if (!groupClients.isEmpty()) { for (Client client : groupClients) { HashMap smsParams = processRepaymentDataForSms(loanTransaction, client); - for (String key : campaignParams.keySet()) { - String value = campaignParams.get(key); + for (Map.Entry entry : campaignParams.entrySet()) { + String value = entry.getValue(); String spvalue = null; - boolean spkeycheck = smsParams.containsKey(key); + boolean spkeycheck = smsParams.containsKey(entry.getKey()); if (spkeycheck) { - spvalue = smsParams.get(key).toString(); + spvalue = smsParams.get(entry.getKey()).toString(); } if (spkeycheck && !(value.equals("-1") || spvalue.equals(value))) { - if (key.equals("officeId")) { + if (entry.getKey().equals("officeId")) { Long officeId = Long.valueOf(value); Office campaignOffice = this.officeRepository.findById(Long.valueOf(value)) .orElseThrow(() -> new OfficeNotFoundException(officeId)); @@ -244,15 +244,15 @@ public class SmsCampaignDomainServiceImpl implements SmsCampaignDomainService { }); HashMap smsParams = processSavingsTransactionDataForSms(savingsTransaction, client); - for (String key : campaignParams.keySet()) { - String value = campaignParams.get(key); + for (Map.Entry entry : campaignParams.entrySet()) { + String value = entry.getValue(); String spvalue = null; - boolean spkeycheck = smsParams.containsKey(key); + boolean spkeycheck = smsParams.containsKey(entry.getKey()); if (spkeycheck) { - spvalue = smsParams.get(key).toString(); + spvalue = smsParams.get(entry.getKey()).toString(); } if (spkeycheck && !(value.equals("-1") || spvalue.equals(value))) { - if (key.equals("officeId")) { + if (entry.getKey().equals("officeId")) { Long officeId = Long.valueOf(value); Office campaignOffice = this.officeRepository.findById(officeId) .orElseThrow(() -> new OfficeNotFoundException(officeId)); diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/service/SmsCampaignDropdownReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/service/SmsCampaignDropdownReadPlatformServiceImpl.java index 61e5df6d2..c333a4203 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/service/SmsCampaignDropdownReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/service/SmsCampaignDropdownReadPlatformServiceImpl.java @@ -19,7 +19,6 @@ package org.apache.fineract.infrastructure.campaigns.sms.service; import java.net.URI; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; @@ -72,7 +71,7 @@ public class SmsCampaignDropdownReadPlatformServiceImpl implements SmsCampaignDr @Override public Collection retrieveSmsProviders() { - Collection smsProviderOptions = new ArrayList<>(); + Collection smsProviderOptions; Map hostConfig = this.smsConfigUtils.getMessageGateWayRequestURI("smsbridges", null); URI uri = (URI) hostConfig.get("uri"); HttpEntity entity = (HttpEntity) hostConfig.get("entity"); @@ -80,8 +79,7 @@ public class SmsCampaignDropdownReadPlatformServiceImpl implements SmsCampaignDr ResponseEntity> responseOne = null; try { - responseOne = restTemplate.exchange(uri, HttpMethod.GET, entity, - new ParameterizedTypeReference>() {}); + responseOne = restTemplate.exchange(uri, HttpMethod.GET, entity, new ParameterizedTypeReference<>() {}); } catch (ResourceAccessException ex) { LOG.debug("Mobile service provider {} not available", uri, ex); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/OkHttp3Config.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/OkHttp3Config.java new file mode 100644 index 000000000..eb5d81c1b --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/OkHttp3Config.java @@ -0,0 +1,71 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.fineract.infrastructure.core.config; + +import java.security.SecureRandom; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import okhttp3.OkHttpClient; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Slf4j +@RequiredArgsConstructor +@Configuration +public class OkHttp3Config { + + private final FineractProperties fineractProperties; + + @Bean + public OkHttpClient okHttpClient() throws Exception { + var okBuilder = new OkHttpClient.Builder(); + + if (Boolean.TRUE.equals(fineractProperties.getInsecureHttpClient())) { + final X509TrustManager insecureX509TrustManager = new X509TrustManager() { + + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {}// NOSONAR + + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {}// NOSONAR + + @Override + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[] {}; + } + }; + + SSLContext insecureSSLContext = SSLContext.getInstance("TLS"); + insecureSSLContext.init(null, new TrustManager[] { insecureX509TrustManager }, new SecureRandom()); + + okBuilder.sslSocketFactory(insecureSSLContext.getSocketFactory(), insecureX509TrustManager); + HostnameVerifier insecureHostnameVerifier = (hostname, session) -> true;// NOSONAR + okBuilder.hostnameVerifier(insecureHostnameVerifier); + } + + return okBuilder.build(); + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/cache/CacheConfig.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/cache/CacheConfig.java index e4202ae34..216328bb8 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/cache/CacheConfig.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/cache/CacheConfig.java @@ -61,25 +61,53 @@ public class CacheConfig { CacheConfigurationBuilder.newCacheConfigurationBuilder(Object.class, Object.class, ResourcePoolsBuilder.heap(10000)) .withExpiry(ExpiryPolicyBuilder.noExpiration()).build()); - cacheManager.createCache("users", defaultTemplate); - cacheManager.createCache("usersByUsername", defaultTemplate); - cacheManager.createCache("tenantsById", defaultTemplate); - cacheManager.createCache("offices", defaultTemplate); - cacheManager.createCache("officesForDropdown", defaultTemplate); - cacheManager.createCache("officesById", defaultTemplate); - cacheManager.createCache("charges", defaultTemplate); - cacheManager.createCache("funds", defaultTemplate); - cacheManager.createCache("code_values", defaultTemplate); - cacheManager.createCache("codes", defaultTemplate); - cacheManager.createCache("hooks", defaultTemplate); - cacheManager.createCache("tfConfig", defaultTemplate); - cacheManager.createCache(CONFIG_BY_NAME_CACHE_NAME, defaultTemplate); + if (cacheManager.getCache("users") == null) { + cacheManager.createCache("users", defaultTemplate); + } + if (cacheManager.getCache("usersByUsername") == null) { + cacheManager.createCache("usersByUsername", defaultTemplate); + } + if (cacheManager.getCache("tenantsById") == null) { + cacheManager.createCache("tenantsById", defaultTemplate); + } + if (cacheManager.getCache("offices") == null) { + cacheManager.createCache("offices", defaultTemplate); + } + if (cacheManager.getCache("officesForDropdown") == null) { + cacheManager.createCache("officesForDropdown", defaultTemplate); + } + if (cacheManager.getCache("officesById") == null) { + cacheManager.createCache("officesById", defaultTemplate); + } + if (cacheManager.getCache("charges") == null) { + cacheManager.createCache("charges", defaultTemplate); + } + if (cacheManager.getCache("funds") == null) { + cacheManager.createCache("funds", defaultTemplate); + } + if (cacheManager.getCache("code_values") == null) { + cacheManager.createCache("code_values", defaultTemplate); + } + if (cacheManager.getCache("codes") == null) { + cacheManager.createCache("codes", defaultTemplate); + } + if (cacheManager.getCache("hooks") == null) { + cacheManager.createCache("hooks", defaultTemplate); + } + if (cacheManager.getCache("tfConfig") == null) { + cacheManager.createCache("tfConfig", defaultTemplate); + } + if (cacheManager.getCache(CONFIG_BY_NAME_CACHE_NAME) == null) { + cacheManager.createCache(CONFIG_BY_NAME_CACHE_NAME, defaultTemplate); + } javax.cache.configuration.Configuration accessTokenTemplate = Eh107Configuration.fromEhcacheCacheConfiguration( CacheConfigurationBuilder.newCacheConfigurationBuilder(Object.class, Object.class, ResourcePoolsBuilder.heap(10000)) .withExpiry(ExpiryPolicyBuilder.timeToIdleExpiration(Duration.ofHours(2))).build()); - cacheManager.createCache("userTFAccessToken", accessTokenTemplate); + if (cacheManager.getCache("userTFAccessToken") == null) { + cacheManager.createCache("userTFAccessToken", accessTokenTemplate); + } return cacheManager; } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/migration/TenantPasswordEncryptionTask.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/migration/TenantPasswordEncryptionTask.java index e8d693fd8..63822ce3a 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/migration/TenantPasswordEncryptionTask.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/migration/TenantPasswordEncryptionTask.java @@ -21,6 +21,8 @@ package org.apache.fineract.infrastructure.core.service.migration; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.sql.ResultSet; import java.sql.Statement; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import liquibase.change.custom.CustomTaskChange; import liquibase.database.Database; import liquibase.database.jvm.JdbcConnection; @@ -42,6 +44,9 @@ public class TenantPasswordEncryptionTask implements CustomTaskChange, Applicati private static DatabasePasswordEncryptor databasePasswordEncryptor; + // NOTE: workaround for double execution bug; see: https://github.com/liquibase/liquibase/issues/3945 + private Map done = new ConcurrentHashMap<>(); + @Override public void execute(Database database) throws CustomChangeException { JdbcConnection dbConn = (JdbcConnection) database.getConnection(); // autocommit is false @@ -50,16 +55,18 @@ public class TenantPasswordEncryptionTask implements CustomTaskChange, Applicati try (ResultSet rs = selectStatement.executeQuery("SELECT id, schema_password FROM tenant_server_connections")) { while (rs.next()) { String id = rs.getString("id"); - String schemaPassword = rs.getString("schema_password"); - String encryptedPassword = TenantPasswordEncryptionTask.databasePasswordEncryptor.encrypt(schemaPassword); + if (!Boolean.TRUE.equals(done.get(id))) { + String schemaPassword = rs.getString("schema_password"); + String encryptedPassword = TenantPasswordEncryptionTask.databasePasswordEncryptor.encrypt(schemaPassword); - String updateSql = String.format( - "update tenant_server_connections set schema_password = '%s', master_password_hash = '%s' where id = %s", - encryptedPassword, TenantPasswordEncryptionTask.databasePasswordEncryptor.getMasterPasswordHash(), id); - updateStatement.execute(updateSql); + String updateSql = String.format( + "update tenant_server_connections set schema_password = '%s', master_password_hash = '%s' where id = %s", + encryptedPassword, TenantPasswordEncryptionTask.databasePasswordEncryptor.getMasterPasswordHash(), id); + updateStatement.execute(updateSql); + done.put(id, true); + } } } - } catch (Exception e) { throw new CustomChangeException(e); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/migration/TenantReadOnlyPasswordEncryptionTask.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/migration/TenantReadOnlyPasswordEncryptionTask.java index e019ae163..a3537ae9f 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/migration/TenantReadOnlyPasswordEncryptionTask.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/migration/TenantReadOnlyPasswordEncryptionTask.java @@ -21,6 +21,8 @@ package org.apache.fineract.infrastructure.core.service.migration; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.sql.ResultSet; import java.sql.Statement; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import liquibase.change.custom.CustomTaskChange; import liquibase.database.Database; import liquibase.database.jvm.JdbcConnection; @@ -42,6 +44,9 @@ public class TenantReadOnlyPasswordEncryptionTask implements CustomTaskChange, A private static DatabasePasswordEncryptor databasePasswordEncryptor; + // NOTE: workaround for double execution bug; see: https://github.com/liquibase/liquibase/issues/3945 + private Map done = new ConcurrentHashMap<>(); + @Override public void execute(Database database) throws CustomChangeException { JdbcConnection dbConn = (JdbcConnection) database.getConnection(); // autocommit is false @@ -51,17 +56,20 @@ public class TenantReadOnlyPasswordEncryptionTask implements CustomTaskChange, A "SELECT id, readonly_schema_password FROM tenant_server_connections WHERE readonly_schema_password IS NOT NULL")) { while (rs.next()) { String id = rs.getString("id"); - String readOnlySchemaPassword = rs.getString("readonly_schema_password"); - String encryptedPassword = TenantReadOnlyPasswordEncryptionTask.databasePasswordEncryptor - .encrypt(readOnlySchemaPassword); + if (!Boolean.TRUE.equals(done.get(id))) { + String readOnlySchemaPassword = rs.getString("readonly_schema_password"); + String encryptedPassword = TenantReadOnlyPasswordEncryptionTask.databasePasswordEncryptor + .encrypt(readOnlySchemaPassword); - String updateSql = String.format( - "update tenant_server_connections set readonly_schema_password = '%s', master_password_hash = '%s' where id = %s", - encryptedPassword, TenantReadOnlyPasswordEncryptionTask.databasePasswordEncryptor.getMasterPasswordHash(), id); - updateStatement.execute(updateSql); + String updateSql = String.format( + "update tenant_server_connections set readonly_schema_password = '%s', master_password_hash = '%s' where id = %s", + encryptedPassword, TenantReadOnlyPasswordEncryptionTask.databasePasswordEncryptor.getMasterPasswordHash(), + id); + updateStatement.execute(updateSql); + done.put(id, true); + } } } - } catch (Exception e) { throw new CustomChangeException(e); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/creditbureau/service/ThitsaWorksCreditBureauIntegrationWritePlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/creditbureau/service/ThitsaWorksCreditBureauIntegrationWritePlatformServiceImpl.java index 888a8d0a6..8316d71bd 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/creditbureau/service/ThitsaWorksCreditBureauIntegrationWritePlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/creditbureau/service/ThitsaWorksCreditBureauIntegrationWritePlatformServiceImpl.java @@ -39,6 +39,8 @@ import java.util.Optional; import java.util.function.BiFunction; import java.util.function.Function; import java.util.function.Supplier; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import okhttp3.HttpUrl; import okhttp3.MediaType; import okhttp3.MultipartBody; @@ -65,18 +67,14 @@ import org.apache.fineract.infrastructure.creditbureau.domain.TokenRepositoryWra import org.apache.fineract.infrastructure.creditbureau.serialization.CreditBureauTokenCommandFromApiJsonDeserializer; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.glassfish.jersey.media.multipart.FormDataContentDisposition; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -@Component +@Slf4j +@RequiredArgsConstructor @Service public class ThitsaWorksCreditBureauIntegrationWritePlatformServiceImpl implements ThitsaWorksCreditBureauIntegrationWritePlatformService { - private static final Logger LOG = LoggerFactory.getLogger(ThitsaWorksCreditBureauIntegrationWritePlatformServiceImpl.class); public static final String UPLOAD_CREDIT_REPORT = "UploadCreditReport"; public static final String RESPONSE_MESSAGE = "ResponseMessage"; public static final String IS_NOT_AVAILABLE_SUFFIX = ".is.not.available"; @@ -85,29 +83,8 @@ public class ThitsaWorksCreditBureauIntegrationWritePlatformServiceImpl implemen private final TokenRepositoryWrapper tokenRepositoryWrapper; private final CreditBureauConfigurationRepositoryWrapper configDataRepository; private final CreditBureauTokenCommandFromApiJsonDeserializer fromApiJsonDeserializer; - private final OkHttpClient client; - @Autowired - public ThitsaWorksCreditBureauIntegrationWritePlatformServiceImpl(final PlatformSecurityContext context, - final FromJsonHelper fromApiJsonHelper, final TokenRepositoryWrapper tokenRepositoryWrapper, - final CreditBureauConfigurationRepositoryWrapper configDataRepository, - final CreditBureauTokenCommandFromApiJsonDeserializer fromApiJsonDeserializer) { - this(new OkHttpClient(), context, fromApiJsonHelper, tokenRepositoryWrapper, configDataRepository, fromApiJsonDeserializer); - } - - public ThitsaWorksCreditBureauIntegrationWritePlatformServiceImpl(final OkHttpClient okHttpClient, - final PlatformSecurityContext context, final FromJsonHelper fromApiJsonHelper, - final TokenRepositoryWrapper tokenRepositoryWrapper, final CreditBureauConfigurationRepositoryWrapper configDataRepository, - final CreditBureauTokenCommandFromApiJsonDeserializer fromApiJsonDeserializer) { - this.client = okHttpClient; - this.context = context; - this.tokenRepositoryWrapper = tokenRepositoryWrapper; - this.configDataRepository = configDataRepository; - this.fromApiJsonHelper = fromApiJsonHelper; - this.fromApiJsonDeserializer = fromApiJsonDeserializer; - } - @Transactional @Override public String okHttpConnectionMethod(String userName, String password, String subscriptionKey, String subscriptionId, String url, @@ -151,7 +128,7 @@ public class ThitsaWorksCreditBureauIntegrationWritePlatformServiceImpl implemen responseMessage = response.body().string(); } catch (IOException e) { - LOG.error("error occured in HTTP request-response method.", e); + log.error("error occured in HTTP request-response method.", e); } if (responseCode != HttpURLConnection.HTTP_OK) { @@ -494,7 +471,7 @@ public class ThitsaWorksCreditBureauIntegrationWritePlatformServiceImpl implemen "creditBureau.Configuration." + configurationParameterName + IS_NOT_AVAILABLE_SUFFIX); } - } catch (NullPointerException ex) { + } catch (Exception ex) { baseDataValidator.reset().failWithCode("creditBureau.configuration.is.not.available"); throw new PlatformApiDataValidationException("creditBureau.Configuration.is.not.available" + ex, "creditBureau.Configuration.is.not.available", dataValidationErrors); diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadReportingServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadReportingServiceImpl.java index d116e1a15..b845b2224 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadReportingServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadReportingServiceImpl.java @@ -37,7 +37,6 @@ import java.util.Collection; import java.util.List; import java.util.Locale; import java.util.Map; -import java.util.Set; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.csv.CSVFormat; @@ -133,11 +132,8 @@ public class ReadReportingServiceImpl implements ReadReportingService { String sql = getSql(name, type); - final Set keys = queryParams.keySet(); - for (final String key : keys) { - final String pValue = queryParams.get(key); - // LOG.info("({} : {})", key, pValue); - sql = this.genericDataService.replace(sql, key, pValue); + for (Map.Entry entry : queryParams.entrySet()) { + sql = this.genericDataService.replace(sql, entry.getKey(), entry.getValue()); } final AppUser currentUser = this.context.authenticatedUser(); @@ -238,14 +234,9 @@ public class ReadReportingServiceImpl implements ReadReportingService { row = element.getRow(); rSize = row.size(); for (int j = 0; j < rSize; j++) { - currColType = columnHeaders.get(j).getColumnType(); currVal = (String) row.get(j); if (currVal != null) { - if (currColType.isNumericType()) { - table.addCell(currVal.toString()); - } else { - table.addCell(currVal.toString()); - } + table.addCell(currVal); } } } @@ -453,11 +444,8 @@ public class ReadReportingServiceImpl implements ReadReportingService { private String sqlToRunForSmsEmailCampaign(final String name, final String type, final Map queryParams) { String sql = getSql(name, type); - final Set keys = queryParams.keySet(); - for (String key : keys) { - final String pValue = queryParams.get(key); - key = "${" + key + "}"; - sql = this.genericDataService.replace(sql, key, pValue); + for (Map.Entry entry : queryParams.entrySet()) { + sql = this.genericDataService.replace(sql, "${" + entry.getKey() + "}", entry.getValue()); } sql = this.genericDataService.wrapSQL(sql); diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImpl.java index 022ad5ee6..b8d587e71 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImpl.java @@ -371,7 +371,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ private void registerDataTable(final String entityName, final String dataTableName, final String entitySubType, final Integer category, final String permissionsSql) { - EntityTables entityTable = resolveEntity(entityName); + resolveEntity(entityName); validateDatatableName(dataTableName); validateDataTableExists(dataTableName); @@ -1294,16 +1294,16 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ List.of(entityTable.getForeignKeyColumnNameOnDatatable(), CREATEDAT_FIELD_NAME, UPDATEDAT_FIELD_NAME)); LocalDateTime auditDateTime = DateUtils.getAuditLocalDateTime(); ArrayList params = new ArrayList<>(List.of(appTableId, auditDateTime, auditDateTime)); - for (String key : dataParams.keySet()) { - if (isTechnicalParam(key)) { + for (Map.Entry entry : dataParams.entrySet()) { + if (isTechnicalParam(entry.getKey())) { continue; } - ResultsetColumnHeaderData columnHeader = SearchUtil.validateToJdbcColumn(key, headersByName, false); + ResultsetColumnHeaderData columnHeader = SearchUtil.validateToJdbcColumn(entry.getKey(), headersByName, false); if (!isUserInsertable(entityTable, columnHeader)) { continue; } insertColumns.add(columnHeader.getColumnName()); - params.add(SearchUtil.parseJdbcColumnValue(columnHeader, dataParams.get(key), dateFormat, dateTimeFormat, locale, false, + params.add(SearchUtil.parseJdbcColumnValue(columnHeader, entry.getValue(), dateFormat, dateTimeFormat, locale, false, sqlGenerator)); } if (addScore) { @@ -1403,17 +1403,17 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ ArrayList updateColumns = new ArrayList<>(List.of(UPDATEDAT_FIELD_NAME)); ArrayList params = new ArrayList<>(List.of(DateUtils.getAuditLocalDateTime())); final HashMap changes = new HashMap<>(); - for (String key : dataParams.keySet()) { - if (isTechnicalParam(key)) { + for (Map.Entry entry : dataParams.entrySet()) { + if (isTechnicalParam(entry.getKey())) { continue; } - ResultsetColumnHeaderData columnHeader = SearchUtil.validateToJdbcColumn(key, headersByName, false); + ResultsetColumnHeaderData columnHeader = SearchUtil.validateToJdbcColumn(entry.getKey(), headersByName, false); if (!isUserUpdatable(entityTable, columnHeader)) { continue; } String columnName = columnHeader.getColumnName(); Object existingValue = valuesByHeader.get(columnHeader); - Object columnValue = SearchUtil.parseColumnValue(columnHeader, dataParams.get(key), dateFormat, dateTimeFormat, locale, false, + Object columnValue = SearchUtil.parseColumnValue(columnHeader, entry.getValue(), dateFormat, dateTimeFormat, locale, false, sqlGenerator); if ((columnHeader.getColumnType().isDecimalType() && MathUtil.isEqualTo((BigDecimal) existingValue, (BigDecimal) columnValue)) || (existingValue == null ? columnValue == null : existingValue.equals(columnValue))) { diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/documentmanagement/service/ImageWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/documentmanagement/service/ImageWritePlatformServiceJpaRepositoryImpl.java index 21035ca3c..09f75bcac 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/documentmanagement/service/ImageWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/documentmanagement/service/ImageWritePlatformServiceJpaRepositoryImpl.java @@ -134,15 +134,13 @@ public class ImageWritePlatformServiceJpaRepositoryImpl implements ImageWritePla private CommandProcessingResult updateImage(final Object owner, final String imageLocation, final StorageType storageType) { Image image = null; Long clientId = null; - if (owner instanceof Client) { - Client client = (Client) owner; + if (owner instanceof Client client) { image = client.getImage(); clientId = client.getId(); image = createImage(image, imageLocation, storageType); client.setImage(image); this.clientRepositoryWrapper.save(client); - } else if (owner instanceof Staff) { - Staff staff = (Staff) owner; + } else if (owner instanceof Staff staff) { image = staff.getImage(); clientId = staff.getId(); image = createImage(image, imageLocation, storageType); @@ -150,7 +148,9 @@ public class ImageWritePlatformServiceJpaRepositoryImpl implements ImageWritePla this.staffRepositoryWrapper.save(staff); } - this.imageRepository.save(image); + if (image != null) { + this.imageRepository.save(image); + } return CommandProcessingResult.resourceResult(clientId); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/producer/kafka/KafkaExternalEventProducer.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/producer/kafka/KafkaExternalEventProducer.java index 9cf815e41..952a7b552 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/producer/kafka/KafkaExternalEventProducer.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/producer/kafka/KafkaExternalEventProducer.java @@ -58,10 +58,9 @@ public class KafkaExternalEventProducer implements ExternalEventProducer { List>> sendResults = new ArrayList<>(); measure(() -> { Set keys = partitions.keySet(); - for (Long key : keys) { - List messages = partitions.get(key); - for (byte[] message : messages) { - sendResults.add(externalEventsKafkaTemplate.send(topicName, key, message)); + for (Map.Entry> entry : partitions.entrySet()) { + for (byte[] message : entry.getValue()) { + sendResults.add(externalEventsKafkaTemplate.send(topicName, entry.getKey(), message)); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/SchedulerJobListener.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/SchedulerJobListener.java index 33a560366..6278eba1c 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/SchedulerJobListener.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/SchedulerJobListener.java @@ -47,7 +47,6 @@ import org.springframework.stereotype.Component; @RequiredArgsConstructor public class SchedulerJobListener implements JobListener { - private final String name = SchedulerServiceConstants.DEFAULT_LISTENER_NAME; private final SchedularWritePlatformService schedularService; private final AppUserRepositoryWrapper userRepository; private final BusinessDateReadPlatformService businessDateReadPlatformService; @@ -55,7 +54,7 @@ public class SchedulerJobListener implements JobListener { @Override public String getName() { - return this.name; + return SchedulerServiceConstants.DEFAULT_LISTENER_NAME; } @Override diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/report/service/ReportingProcessService.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/report/service/ReportingProcessService.java index 1061815f3..314063278 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/report/service/ReportingProcessService.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/report/service/ReportingProcessService.java @@ -23,7 +23,6 @@ import jakarta.ws.rs.core.Response; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Set; import org.apache.fineract.infrastructure.dataqueries.data.ReportExportType; import org.apache.fineract.infrastructure.security.utils.SQLInjectionValidator; @@ -35,11 +34,10 @@ public interface ReportingProcessService { default Map getReportParams(final MultivaluedMap queryParams) { final Map reportParams = new HashMap<>(); - final Set keys = queryParams.keySet(); - for (final String k : keys) { - if (k.startsWith("R_")) { - String pKey = "${" + k.substring(2) + "}"; - String pValue = queryParams.get(k).get(0); + for (Map.Entry> entry : queryParams.entrySet()) { + if (entry.getKey().startsWith("R_")) { + String pKey = "${" + entry.getKey().substring(2) + "}"; + String pValue = entry.getValue().get(0); SQLInjectionValidator.validateSQLInput(pValue); reportParams.put(pKey, pValue); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/sms/api/SmsApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/sms/api/SmsApiResource.java index 841a509ef..e0242f269 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/sms/api/SmsApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/sms/api/SmsApiResource.java @@ -59,7 +59,7 @@ import org.springframework.stereotype.Component; @RequiredArgsConstructor public class SmsApiResource { - private final String resourceNameForPermissions = "SMS"; + private static final String RESOURCE_NAME_FOR_PERMISSIONS = "SMS"; private final PlatformSecurityContext context; private final SmsReadPlatformService readPlatformService; @@ -69,7 +69,7 @@ public class SmsApiResource { @GET public String retrieveAll(@Context final UriInfo uriInfo) { - context.authenticatedUser().validateHasReadPermission(resourceNameForPermissions); + context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSIONS); final Collection smsMessages = readPlatformService.retrieveAll(); final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters()); return toApiJsonSerializer.serialize(settings, smsMessages); @@ -98,7 +98,7 @@ public class SmsApiResource { @QueryParam("dateFormat") final String rawDateFormat, @QueryParam("offset") final Integer offset, @QueryParam("limit") final Integer limit, @QueryParam("orderBy") final String orderBy, @QueryParam("sortOrder") final String sortOrder) { - context.authenticatedUser().validateHasReadPermission(resourceNameForPermissions); + context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSIONS); final SearchParameters searchParameters = SearchParameters.forSMSCampaign(offset, limit, orderBy, sortOrder); final DateFormat dateFormat = StringUtils.isBlank(rawDateFormat) ? null : new DateFormat(rawDateFormat); diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/survey/api/SurveyApiResourceSwagger.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/survey/api/SurveyApiResourceSwagger.java index 8f26777ff..4cd6ba662 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/survey/api/SurveyApiResourceSwagger.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/survey/api/SurveyApiResourceSwagger.java @@ -86,7 +86,7 @@ final class SurveyApiResourceSwagger { @Schema(example = "201") public Long ppi_fryingpans_cd_q10_fryingpans; @Schema(example = "2014-12-02 20:30:00") - public ZonedDateTime Date; + public ZonedDateTime date; @Schema(example = "Y-m-d H:i:s") public ZonedDateTime dateFormat; @Schema(example = "en_GB") diff --git a/fineract-provider/src/main/java/org/apache/fineract/organisation/teller/api/TellerApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/organisation/teller/api/TellerApiResource.java index b88125466..bd42683dd 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/organisation/teller/api/TellerApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/organisation/teller/api/TellerApiResource.java @@ -308,8 +308,10 @@ public class TellerApiResource { @QueryParam("limit") @Parameter(description = "limit") final Integer limit, @QueryParam("orderBy") @Parameter(description = "orderBy") final String orderBy, @QueryParam("sortOrder") @Parameter(description = "sortOrder") final String sortOrder) { - final TellerData teller = this.readPlatformService.findTeller(tellerId); - final CashierData cashier = this.readPlatformService.findCashier(cashierId); + // TODO: can we remove these 2 calls? we don't use the results, but left it here in case something is done in + // the functions + this.readPlatformService.findTeller(tellerId); + this.readPlatformService.findCashier(cashierId); final LocalDate fromDate = null; final LocalDate toDate = null; @@ -334,8 +336,10 @@ public class TellerApiResource { @QueryParam("limit") @Parameter(description = "limit") final Integer limit, @QueryParam("orderBy") @Parameter(description = "orderBy") final String orderBy, @QueryParam("sortOrder") @Parameter(description = "sortOrder") final String sortOrder) { - final TellerData teller = this.readPlatformService.findTeller(tellerId); - final CashierData cashier = this.readPlatformService.findCashier(cashierId); + // TODO: can we remove these 2 calls? we don't use the results, but left it here in case something is done in + // the functions + this.readPlatformService.findTeller(tellerId); + this.readPlatformService.findCashier(cashierId); final LocalDate fromDate = null; final LocalDate toDate = null; diff --git a/fineract-provider/src/main/java/org/apache/fineract/organisation/teller/service/TellerWritePlatformServiceJpaImpl.java b/fineract-provider/src/main/java/org/apache/fineract/organisation/teller/service/TellerWritePlatformServiceJpaImpl.java index 3f649405e..b00b5c98b 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/organisation/teller/service/TellerWritePlatformServiceJpaImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/organisation/teller/service/TellerWritePlatformServiceJpaImpl.java @@ -355,8 +355,8 @@ public class TellerWritePlatformServiceJpaImpl implements TellerWritePlatformSer this.fromApiJsonDeserializer.validateForCashTxnForCashier(command.json()); + // TODO: can we please remove this whole block?!? this is 20 lines of dead code!!! final String entityType = command.stringValueOfParameterNamed("entityType"); - final Long entityId = command.longValueOfParameterNamed("entityId"); if (entityType != null) { if (entityType.equals("loan account")) { // TODO : Check if loan account exists diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/service/AddressReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/service/AddressReadPlatformServiceImpl.java index ebe5660dd..5e0a60f4d 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/service/AddressReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/address/service/AddressReadPlatformServiceImpl.java @@ -65,8 +65,6 @@ public class AddressReadPlatformServiceImpl implements AddressReadPlatformServic final long addressId = rs.getLong("id"); - final long clientId = rs.getLong("client_id"); - final String street = rs.getString("street"); final String address_line_1 = rs.getString("address_line_1"); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/common/domain/ConditionType.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/common/domain/ConditionType.java index ea464426c..dbe9c3147 100755 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/common/domain/ConditionType.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/common/domain/ConditionType.java @@ -18,33 +18,37 @@ */ package org.apache.fineract.portfolio.common.domain; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.Arrays; public enum ConditionType { INVALID(0, "ConditionType.invalid"), // LESSTHAN(1, "ConditionType.lessthan"), // EQUAL(2, "ConditionType.equal"), // + // TODO: fix typo "GREATERTHAN" GRETERTHAN(3, "ConditionType.greterthan"), // NOT_EQUAL(4, "ConditionType.notequal");// private final Integer value; private final String code; - private static final Map intToEnumMap = new HashMap<>(); - - static { - for (final ConditionType type : ConditionType.values()) { - intToEnumMap.put(type.value, type); + public static ConditionType fromInt(final Integer v) { + if (v == null) { + return INVALID; } - } - public static ConditionType fromInt(final Integer ruleTypeValue) { - final ConditionType type = intToEnumMap.get(ruleTypeValue); - return type; + switch (v) { + case 1: + return LESSTHAN; + case 2: + return EQUAL; + case 3: + return GRETERTHAN; + case 4: + return NOT_EQUAL; + default: + return INVALID; + } } ConditionType(final Integer value, final String code) { @@ -65,34 +69,13 @@ public enum ConditionType { return this.code; } - public boolean isConditionTypeEqual() { - return ConditionType.EQUAL.getValue().equals(this.value); - } - - public boolean isConditionTypeGreterThan() { - return ConditionType.GRETERTHAN.getValue().equals(this.value); - } - - public boolean isConditionTypeNotEqual() { - return ConditionType.NOT_EQUAL.getValue().equals(this.value); - } - - public boolean isConditionTypeLessThan() { - return ConditionType.LESSTHAN.getValue().equals(this.value); - } - + // TODO: why not just use the enum values... just more boilerplate code here!! public boolean isInvalid() { return ConditionType.INVALID.getValue().equals(this.value); } + // TODO: do we really need this?!? public static Object[] integerValues() { - final List values = new ArrayList<>(); - for (final ConditionType enumType : values()) { - if (!enumType.isInvalid()) { - values.add(enumType.getValue()); - } - } - - return values.toArray(); + return Arrays.stream(values()).filter(value -> !INVALID.equals(value)).map(value -> value.value).toList().toArray(); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/incentive/InterestIncentiveAttributeName.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/incentive/InterestIncentiveAttributeName.java index b5993c319..ff8208b67 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/incentive/InterestIncentiveAttributeName.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/incentive/InterestIncentiveAttributeName.java @@ -18,10 +18,7 @@ */ package org.apache.fineract.portfolio.interestratechart.incentive; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.Arrays; public enum InterestIncentiveAttributeName { @@ -34,19 +31,21 @@ public enum InterestIncentiveAttributeName { private final Integer value; private final String code; - private static final Map intToEnumMap = new HashMap<>(); - - static { - for (final InterestIncentiveAttributeName type : InterestIncentiveAttributeName.values()) { - intToEnumMap.put(type.value, type); + public static InterestIncentiveAttributeName fromInt(final Integer value) { + switch (value) { + case 2: + return GENDER; + case 3: + return AGE; + case 4: + return CLIENT_TYPE; + case 5: + return CLIENT_CLASSIFICATION; + default: + return INVALID; } } - public static InterestIncentiveAttributeName fromInt(final Integer ruleTypeValue) { - final InterestIncentiveAttributeName type = intToEnumMap.get(ruleTypeValue); - return type; - } - InterestIncentiveAttributeName(final Integer value, final String code) { this.value = value; this.code = code; @@ -65,49 +64,45 @@ public enum InterestIncentiveAttributeName { return this.code; } + // TODO: why not just use the enum values... just more boilerplate code here!! public boolean isGender() { - return InterestIncentiveAttributeName.GENDER.getValue().equals(this.value); + return GENDER.equals(this); } + // TODO: why not just use the enum values... just more boilerplate code here!! public boolean isAge() { - return InterestIncentiveAttributeName.AGE.getValue().equals(this.value); + return AGE.equals(this); } + // TODO: why not just use the enum values... just more boilerplate code here!! public boolean isClientType() { - return InterestIncentiveAttributeName.CLIENT_TYPE.getValue().equals(this.value); + return CLIENT_TYPE.equals(this); } + // TODO: why not just use the enum values... just more boilerplate code here!! public boolean isClientClassification() { - return InterestIncentiveAttributeName.CLIENT_CLASSIFICATION.getValue().equals(this.value); + return CLIENT_CLASSIFICATION.equals(this); } + // TODO: why not just use the enum values... just more boilerplate code here!! public boolean isInvalid() { - return InterestIncentiveAttributeName.INVALID.getValue().equals(this.value); + return INVALID.equals(this); } + // TODO: why not just use the enum values... just more boilerplate code here!! public static boolean isCodeValueAttribute(InterestIncentiveAttributeName attributeName) { - boolean isCodeValue = false; switch (attributeName) { case GENDER: case CLIENT_TYPE: case CLIENT_CLASSIFICATION: - isCodeValue = true; - break; + return true; default: - break; + return false; } - return isCodeValue; } + // TODO: do we really need this?!? public static Object[] integerValues() { - final List values = new ArrayList<>(); - for (final InterestIncentiveAttributeName enumType : values()) { - if (!enumType.isInvalid()) { - values.add(enumType.getValue()); - } - } - - return values.toArray(); + return Arrays.stream(values()).filter(value -> !INVALID.equals(value)).map(value -> value.value).toList().toArray(); } - } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/incentive/InterestIncentiveEntityType.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/incentive/InterestIncentiveEntityType.java index b5008630e..8f00b48cb 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/incentive/InterestIncentiveEntityType.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/incentive/InterestIncentiveEntityType.java @@ -18,10 +18,7 @@ */ package org.apache.fineract.portfolio.interestratechart.incentive; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.Arrays; public enum InterestIncentiveEntityType { @@ -32,17 +29,19 @@ public enum InterestIncentiveEntityType { private final Integer value; private final String code; - private static final Map intToEnumMap = new HashMap<>(); - - static { - for (final InterestIncentiveEntityType type : InterestIncentiveEntityType.values()) { - intToEnumMap.put(type.value, type); + public static InterestIncentiveEntityType fromInt(final Integer v) { + if (v == null) { + return INVALID; } - } - public static InterestIncentiveEntityType fromInt(final Integer ruleTypeValue) { - final InterestIncentiveEntityType type = intToEnumMap.get(ruleTypeValue); - return type; + switch (v) { + case 2: + return CUSTOMER; + case 3: + return ACCOUNT; + default: + return INVALID; + } } InterestIncentiveEntityType(final Integer value, final String code) { @@ -64,21 +63,15 @@ public enum InterestIncentiveEntityType { } public boolean isCustomer() { - return InterestIncentiveEntityType.CUSTOMER.getValue().equals(this.value); + return CUSTOMER.equals(this); } public boolean isInvalid() { - return InterestIncentiveEntityType.INVALID.getValue().equals(this.value); + return INVALID.equals(this); } + // TODO: do we really need this?!? public static Object[] integerValues() { - final List values = new ArrayList<>(); - for (final InterestIncentiveEntityType enumType : values()) { - if (!enumType.isInvalid()) { - values.add(enumType.getValue()); - } - } - - return values.toArray(); + return Arrays.stream(values()).filter(value -> !INVALID.equals(value)).map(value -> value.value).toList().toArray(); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/incentive/InterestIncentiveType.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/incentive/InterestIncentiveType.java index f14014d4d..cc55c4e82 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/incentive/InterestIncentiveType.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/incentive/InterestIncentiveType.java @@ -18,10 +18,7 @@ */ package org.apache.fineract.portfolio.interestratechart.incentive; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.Arrays; public enum InterestIncentiveType { @@ -32,17 +29,19 @@ public enum InterestIncentiveType { private final Integer value; private final String code; - private static final Map intToEnumMap = new HashMap<>(); - - static { - for (final InterestIncentiveType type : InterestIncentiveType.values()) { - intToEnumMap.put(type.value, type); + public static InterestIncentiveType fromInt(final Integer v) { + if (v == null) { + return INVALID; } - } - public static InterestIncentiveType fromInt(final Integer ruleTypeValue) { - final InterestIncentiveType type = intToEnumMap.get(ruleTypeValue); - return type; + switch (v) { + case 2: + return FIXED; + case 3: + return INCENTIVE; + default: + return INVALID; + } } InterestIncentiveType(final Integer value, final String code) { @@ -63,27 +62,23 @@ public enum InterestIncentiveType { return this.code; } + // TODO: why not just use the enum values... just more boilerplate code here!! public boolean isIncentive() { - return InterestIncentiveType.INCENTIVE.getValue().equals(this.value); + return INCENTIVE.equals(this); } + // TODO: why not just use the enum values... just more boilerplate code here!! public boolean isFixed() { - return InterestIncentiveType.FIXED.getValue().equals(this.value); + return FIXED.equals(this); } + // TODO: why not just use the enum values... just more boilerplate code here!! public boolean isInvalid() { - return InterestIncentiveType.INVALID.getValue().equals(this.value); + return INVALID.equals(this); } + // TODO: do we really need this?!? public static Object[] integerValues() { - final List values = new ArrayList<>(); - for (final InterestIncentiveType enumType : values()) { - if (!enumType.isInvalid()) { - values.add(enumType.getValue()); - } - } - - return values.toArray(); + return Arrays.stream(values()).filter(value -> !INVALID.equals(value)).map(value -> value.value).toList().toArray(); } - } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanTransactionsApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanTransactionsApiResource.java index 1e84c8026..c9eb31fb6 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanTransactionsApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanTransactionsApiResource.java @@ -84,7 +84,7 @@ public class LoanTransactionsApiResource { private final Set responseDataParameters = new HashSet<>(Arrays.asList("id", "type", "date", "currency", "amount", "externalId", LoanApiConstants.REVERSAL_EXTERNAL_ID_PARAMNAME, LoanApiConstants.REVERSED_ON_DATE_PARAMNAME)); - private final String resourceNameForPermissions = "LOAN"; + private static final String RESOURCE_NAME_FOR_PERMISSIONS = "LOAN"; private final PlatformSecurityContext context; private final LoanReadPlatformService loanReadPlatformService; @@ -414,7 +414,7 @@ public class LoanTransactionsApiResource { private String retrieveTransaction(final Long loanId, final String loanExternalIdStr, final Long transactionId, final String transactionExternalIdStr, final UriInfo uriInfo) { - this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermissions); + this.context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSIONS); ExternalId loanExternalId = ExternalIdFactory.produce(loanExternalIdStr); ExternalId transactionExternalId = ExternalIdFactory.produce(transactionExternalIdStr); @@ -488,7 +488,7 @@ public class LoanTransactionsApiResource { private String retrieveTransactionTemplate(Long loanId, String loanExternalIdStr, String commandParam, UriInfo uriInfo, DateFormat dateFormat, DateParam transactionDateParam, String locale) { - this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermissions); + this.context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSIONS); ExternalId loanExternalId = ExternalIdFactory.produce(loanExternalIdStr); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/jobs/applychargetooverdueloaninstallment/ApplyChargeToOverdueLoanInstallmentTasklet.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/jobs/applychargetooverdueloaninstallment/ApplyChargeToOverdueLoanInstallmentTasklet.java index bce7e33c4..bd09da8fc 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/jobs/applychargetooverdueloaninstallment/ApplyChargeToOverdueLoanInstallmentTasklet.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/jobs/applychargetooverdueloaninstallment/ApplyChargeToOverdueLoanInstallmentTasklet.java @@ -66,23 +66,23 @@ public class ApplyChargeToOverdueLoanInstallmentTasklet implements Tasklet { } List exceptions = new ArrayList<>(); - for (final Long loanId : overdueScheduleData.keySet()) { + for (Map.Entry> entry : overdueScheduleData.entrySet()) { try { - loanChargeWritePlatformService.applyOverdueChargesForLoan(loanId, overdueScheduleData.get(loanId)); + loanChargeWritePlatformService.applyOverdueChargesForLoan(entry.getKey(), entry.getValue()); } catch (final PlatformApiDataValidationException e) { final List errors = e.getErrors(); for (final ApiParameterError error : errors) { - log.error("Apply Charges due for overdue loans failed for account {} with message: {}", loanId, + log.error("Apply Charges due for overdue loans failed for account {} with message: {}", entry.getKey(), error.getDeveloperMessage(), e); } exceptions.add(e); } catch (final AbstractPlatformDomainRuleException e) { - log.error("Apply Charges due for overdue loans failed for account {} with message: {}", loanId, + log.error("Apply Charges due for overdue loans failed for account {} with message: {}", entry.getKey(), e.getDefaultUserMessage(), e); exceptions.add(e); } catch (Exception e) { - log.error("Apply Charges due for overdue loans failed for account {}", loanId, e); + log.error("Apply Charges due for overdue loans failed for account {}", entry.getKey(), e); exceptions.add(e); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/jobs/generateloanlossprovisioning/GenerateLoanlossProvisioningConfig.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/jobs/generateloanlossprovisioning/GenerateLoanlossProvisioningConfig.java index 4fcf6f96a..564549fce 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/jobs/generateloanlossprovisioning/GenerateLoanlossProvisioningConfig.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/jobs/generateloanlossprovisioning/GenerateLoanlossProvisioningConfig.java @@ -39,7 +39,6 @@ public class GenerateLoanlossProvisioningConfig { private JobRepository jobRepository; @Autowired private PlatformTransactionManager transactionManager; - private StepBuilder steps; @Autowired private ProvisioningCriteriaReadPlatformService provisioningCriteriaReadPlatformService; @Autowired diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/jobs/setloandelinquencytags/SetLoanDelinquencyTagsTasklet.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/jobs/setloandelinquencytags/SetLoanDelinquencyTagsTasklet.java index 292be13c1..d1cd7ab39 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/jobs/setloandelinquencytags/SetLoanDelinquencyTagsTasklet.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/jobs/setloandelinquencytags/SetLoanDelinquencyTagsTasklet.java @@ -75,7 +75,7 @@ public class SetLoanDelinquencyTagsTasklet implements Tasklet { loanScheduleDelinquencyData = this.loanRepaymentScheduleInstallmentRepository .fetchLoanScheduleDataByDueDateAndObligationsMet(LoanStatus.ACTIVE.getValue(), businessDate, false, processedLoans); } - processedLoans = applyDelinquencyTagToLoans(loanScheduleDelinquencyData); + applyDelinquencyTagToLoans(loanScheduleDelinquencyData); return RepeatStatus.FINISHED; } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java index 0ec8d3ea1..36764969e 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java @@ -771,10 +771,9 @@ public class LoanScheduleAssembler { graceApplicable = installment.getDueDate(); } } - Collection keySet = adjustDueDateVariations.keySet(); - dueDates.addAll(keySet); - for (final LocalDate date : keySet) { - LocalDate removeDate = adjustDueDateVariations.get(date); + dueDates.addAll(adjustDueDateVariations.keySet()); + for (Map.Entry entry : adjustDueDateVariations.entrySet()) { + LocalDate removeDate = entry.getValue(); if (removeDate != null) { dueDates.remove(removeDate); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java index f15cb39bd..15f359f4b 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java @@ -1453,8 +1453,6 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa @Override public CommandProcessingResult undoApplicationApproval(final Long loanId, final JsonCommand command) { - AppUser currentUser = getAppUserIfPresent(); - this.fromApiJsonDeserializer.validateForUndo(command.json()); final Loan loan = retrieveLoanBy(loanId); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanArrearsAgingServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanArrearsAgingServiceImpl.java index 52a76ac35..795bbec22 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanArrearsAgingServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanArrearsAgingServiceImpl.java @@ -125,14 +125,16 @@ public class LoanArrearsAgingServiceImpl implements LoanArrearsAgingService { @Override public void updateLoanArrearsAgeingDetails(final Loan loan) { - int count = this.jdbcTemplate.queryForObject("select count(mla.loan_id) from m_loan_arrears_aging mla where mla.loan_id =?", - Integer.class, loan.getId()); - String updateStatement = constructUpdateStatement(loan, count == 0); - if (updateStatement == null) { - String deletestatement = "DELETE FROM m_loan_arrears_aging WHERE loan_id=?"; - this.jdbcTemplate.update(deletestatement, loan.getId()); // NOSONAR - } else { - this.jdbcTemplate.update(updateStatement); + if (loan != null) { + int count = this.jdbcTemplate.queryForObject("select count(mla.loan_id) from m_loan_arrears_aging mla where mla.loan_id =?", + Integer.class, loan.getId()); + String updateStatement = constructUpdateStatement(loan, count == 0); + if (updateStatement == null) { + String deletestatement = "DELETE FROM m_loan_arrears_aging WHERE loan_id=?"; + this.jdbcTemplate.update(deletestatement, loan.getId()); // NOSONAR + } else { + this.jdbcTemplate.update(updateStatement); + } } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/meeting/attendance/AttendanceType.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/meeting/attendance/AttendanceType.java index fae510526..f9f1caeb2 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/meeting/attendance/AttendanceType.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/meeting/attendance/AttendanceType.java @@ -48,31 +48,24 @@ public enum AttendanceType { return this.code; } - public static AttendanceType fromInt(final Integer attendanceTypeId) { - - if (attendanceTypeId == null) { - return AttendanceType.INVALID; + public static AttendanceType fromInt(final Integer v) { + if (v == null) { + return INVALID; } - AttendanceType attendanceType = AttendanceType.INVALID; - switch (attendanceTypeId) { + switch (v) { case 1: - attendanceType = AttendanceType.PRESENT; - break; + return PRESENT; case 2: - attendanceType = AttendanceType.ABSENT; - break; + return ABSENT; case 3: - attendanceType = AttendanceType.APPROVED; - break; + return APPROVED; case 4: - attendanceType = AttendanceType.LEAVE; - break; + return LEAVE; case 5: - attendanceType = AttendanceType.LATE; - break; + return LATE; + default: + return INVALID; } - return attendanceType; } - } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/rate/service/RateAssembler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/rate/service/RateAssembler.java index e76923898..9150a9d4c 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/rate/service/RateAssembler.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/rate/service/RateAssembler.java @@ -23,7 +23,6 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import java.util.ArrayList; import java.util.List; -import java.util.Locale; import lombok.RequiredArgsConstructor; import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper; import org.apache.fineract.portfolio.loanproduct.LoanProductConstants; @@ -42,7 +41,6 @@ public class RateAssembler { if (element.isJsonObject()) { final JsonObject topLevelJsonElement = element.getAsJsonObject(); - final Locale locale = this.fromApiJsonHelper.extractLocaleParameter(topLevelJsonElement); if (topLevelJsonElement.has(LoanProductConstants.RATES_PARAM_NAME) && topLevelJsonElement.get(LoanProductConstants.RATES_PARAM_NAME).isJsonArray()) { diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/handler/ApplyAnnualFeeSavingsAccountCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/handler/ApplyAnnualFeeSavingsAccountCommandHandler.java index acd81ac69..a73e44585 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/handler/ApplyAnnualFeeSavingsAccountCommandHandler.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/handler/ApplyAnnualFeeSavingsAccountCommandHandler.java @@ -18,7 +18,6 @@ */ package org.apache.fineract.portfolio.savings.handler; -import java.time.LocalDate; import org.apache.fineract.commands.annotation.CommandType; import org.apache.fineract.commands.handler.NewCommandSourceHandler; import org.apache.fineract.infrastructure.core.api.JsonCommand; @@ -43,9 +42,9 @@ public class ApplyAnnualFeeSavingsAccountCommandHandler implements NewCommandSou @Transactional @Override public CommandProcessingResult processCommand(final JsonCommand command) { - - @SuppressWarnings("unused") - final LocalDate annualFeeTransactionDate = command.localDateValueOfParameterNamed("annualFeeTransactionDate"); + // TODO: why do we keep this class when we literally do nothing here?!? + // final LocalDate annualFeeTransactionDate = + // command.localDateValueOfParameterNamed("annualFeeTransactionDate"); // return // this.writePlatformService.applyAnnualFee(command.getSavingsId(), diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java index d98e18b1b..350618311 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java @@ -264,15 +264,8 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi @Transactional @Override public CommandProcessingResult gsimDeposit(final Long gsimId, final JsonCommand command) { - Long parentSavingId = gsimId; - // GroupSavingsIndividualMonitoringparentSavings=gsimRepository.findById(parentSavingId).get(); - List childSavings = this.savingAccountRepositoryWrapper.findByGsimId(gsimId); - JsonArray savingsArray = command.arrayOfParameterNamed("savingsArray"); - JsonArray childAccounts = command.arrayOfParameterNamed("childAccounts"); - int count = 0; - CommandProcessingResult result = null; for (JsonElement element : savingsArray) { result = deposit(element.getAsJsonObject().get("childAccountId").getAsLong(), @@ -1457,13 +1450,6 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi existingReversedTransactionIds.addAll(account.findCurrentReversedTransactionIdsWithPivotDateConfig()); } - @SuppressWarnings("unused") - private void updateSavingsTransactionsDetails(SavingsAccountData account, Set existingTransactionIds, - Set existingReversedTransactionIds) { - existingTransactionIds.addAll(account.findCurrentTransactionIdsWithPivotDateConfig()); - existingReversedTransactionIds.addAll(account.findCurrentReversedTransactionIdsWithPivotDateConfig()); - } - private void postJournalEntries(final SavingsAccount savingsAccount, final Set existingTransactionIds, final Set existingReversedTransactionIds, final boolean backdatedTxnsAllowedTill) { diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsSchedularInterestPoster.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsSchedularInterestPoster.java index 3a24de735..295d3f55a 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsSchedularInterestPoster.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsSchedularInterestPoster.java @@ -83,8 +83,8 @@ public class SavingsSchedularInterestPoster { } catch (DataAccessException exception) { log.error("Batch update failed due to DataAccessException", exception); errors.add(exception); - } catch (NullPointerException exception) { - log.error("Batch update failed due to NullPointerException", exception); + } catch (Exception exception) { + log.error("Batch update failed", exception); errors.add(exception); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/SharePeriodFrequencyType.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/SharePeriodFrequencyType.java index 2506ee6f7..ed237dc5e 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/SharePeriodFrequencyType.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/SharePeriodFrequencyType.java @@ -18,8 +18,7 @@ */ package org.apache.fineract.portfolio.shareproducts; -import java.util.ArrayList; -import java.util.List; +import java.util.Arrays; /** * An enumeration of supported calendar periods used in savings. @@ -48,39 +47,32 @@ public enum SharePeriodFrequencyType { return this.code; } - public static SharePeriodFrequencyType fromInt(final Integer type) { - SharePeriodFrequencyType repaymentFrequencyType = SharePeriodFrequencyType.INVALID; - if (type != null) { - switch (type) { - case 0: - repaymentFrequencyType = SharePeriodFrequencyType.DAYS; - break; - case 1: - repaymentFrequencyType = SharePeriodFrequencyType.WEEKS; - break; - case 2: - repaymentFrequencyType = SharePeriodFrequencyType.MONTHS; - break; - case 3: - repaymentFrequencyType = SharePeriodFrequencyType.YEARS; - break; - } + public static SharePeriodFrequencyType fromInt(final Integer v) { + if (v == null) { + return INVALID; + } + + switch (v) { + case 0: + return DAYS; + case 1: + return WEEKS; + case 2: + return MONTHS; + case 3: + return YEARS; + default: + return INVALID; } - return repaymentFrequencyType; } + // TODO: why not just use the enum values... just more boilerplate code here!! public boolean isInvalid() { - return this.value.equals(SharePeriodFrequencyType.INVALID.value); + return this.equals(INVALID); } + // TODO: do we really need this?!? public static Object[] integerValues() { - final List values = new ArrayList<>(); - for (final SharePeriodFrequencyType enumType : values()) { - if (!enumType.isInvalid()) { - values.add(enumType.getValue()); - } - } - - return values.toArray(); + return Arrays.stream(values()).filter(value -> !INVALID.equals(value)).map(value -> value.value).toList().toArray(); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/template/service/JpaTemplateDomainService.java b/fineract-provider/src/main/java/org/apache/fineract/template/service/JpaTemplateDomainService.java index 9fe12fe1a..8fc798d81 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/template/service/JpaTemplateDomainService.java +++ b/fineract-provider/src/main/java/org/apache/fineract/template/service/JpaTemplateDomainService.java @@ -81,7 +81,7 @@ public class JpaTemplateDomainService implements TemplateDomainService { template.setText(command.stringValueOfParameterNamed(PROPERTY_TEXT)); template.setEntity(TemplateEntity.values()[command.integerValueSansLocaleOfParameterNamed(PROPERTY_ENTITY)]); final int templateTypeId = command.integerValueSansLocaleOfParameterNamed(PROPERTY_TYPE); - TemplateType type = null; + TemplateType type; switch (templateTypeId) { case 0: type = TemplateType.DOCUMENT; @@ -89,6 +89,8 @@ public class JpaTemplateDomainService implements TemplateDomainService { case 2: type = TemplateType.SMS; break; + default: + type = null; } template.setType(type); diff --git a/fineract-provider/src/main/java/org/apache/fineract/useradministration/service/PermissionWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/useradministration/service/PermissionWritePlatformServiceJpaRepositoryImpl.java index 193ea27c6..c351fb9c5 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/useradministration/service/PermissionWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/useradministration/service/PermissionWritePlatformServiceJpaRepositoryImpl.java @@ -55,19 +55,19 @@ public class PermissionWritePlatformServiceJpaRepositoryImpl implements Permissi final Map commandPermissions = permissionsCommand.getPermissions(); final Map changes = new HashMap<>(); final Map changedPermissions = new HashMap<>(); - for (final String permissionCode : commandPermissions.keySet()) { + for (Map.Entry entry : commandPermissions.entrySet()) { - final Permission permission = findPermissionInCollectionByCode(allPermissions, permissionCode); + final Permission permission = findPermissionInCollectionByCode(allPermissions, entry.getKey()); if (permission.getCode().endsWith("_CHECKER") || permission.getCode().startsWith("READ_") || permission.getGrouping().equalsIgnoreCase("special")) { - throw new PermissionNotFoundException(permissionCode); + throw new PermissionNotFoundException(entry.getKey()); } - final boolean isSelected = commandPermissions.get(permissionCode).booleanValue(); + final boolean isSelected = entry.getValue(); final boolean changed = permission.enableMakerChecker(isSelected); if (changed) { - changedPermissions.put(permissionCode, isSelected); + changedPermissions.put(entry.getKey(), isSelected); this.permissionRepository.saveAndFlush(permission); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/useradministration/service/RoleWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/useradministration/service/RoleWritePlatformServiceJpaRepositoryImpl.java index c06ac8829..8c80ec753 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/useradministration/service/RoleWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/useradministration/service/RoleWritePlatformServiceJpaRepositoryImpl.java @@ -148,13 +148,13 @@ public class RoleWritePlatformServiceJpaRepositoryImpl implements RoleWritePlatf final Map commandPermissions = permissionsCommand.getPermissions(); final Map changes = new HashMap<>(); final Map changedPermissions = new HashMap<>(); - for (final String permissionCode : commandPermissions.keySet()) { - final boolean isSelected = commandPermissions.get(permissionCode).booleanValue(); + for (Map.Entry entry : commandPermissions.entrySet()) { + final boolean isSelected = entry.getValue(); - final Permission permission = findPermissionByCode(allPermissions, permissionCode); + final Permission permission = findPermissionByCode(allPermissions, entry.getKey()); final boolean changed = role.updatePermission(permission, isSelected); if (changed) { - changedPermissions.put(permissionCode, isSelected); + changedPermissions.put(entry.getKey(), isSelected); } } diff --git a/fineract-provider/src/main/resources/application.properties b/fineract-provider/src/main/resources/application.properties index fbbe8662e..81833a3c1 100644 --- a/fineract-provider/src/main/resources/application.properties +++ b/fineract-provider/src/main/resources/application.properties @@ -171,6 +171,8 @@ fineract.sampling.resetPeriodSec=${FINERACT_SAMPLING_RESET_PERIOD_IN_SEC:60} fineract.module.investor.enabled=${FINERACT_MODULE_INVESTOR_ENABLED:true} +fineract.insecure-http-client=${FINERACT_INSECURE_HTTP_CLIENT:true} + # Logging pattern for the console logging.pattern.console=${CONSOLE_LOG_PATTERN:%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(%replace([%X{correlationId}]){'\\[\\]', ''}) %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:%wEx}} logging.pattern.level=%5p [${spring.application.name:},%X{traceId:-},%X{spanId:-}] diff --git a/fineract-provider/src/main/resources/banner.txt b/fineract-provider/src/main/resources/banner.txt index 6103c57b9..31df8c9b4 100644 --- a/fineract-provider/src/main/resources/banner.txt +++ b/fineract-provider/src/main/resources/banner.txt @@ -6,7 +6,7 @@ /_/ \_\ .__/ \__,_|\___|_| |_|\___| |_| |_|_| |_|\___|_| \__,_|\___|\__| |_| -${AnsiStyle.FAINT}${AnsiColor.WHITE}(c) 2015-2022 ${application.title} (https://fineract.apache.org)${AnsiColor.BLACK} +${AnsiStyle.FAINT}${AnsiColor.WHITE}(c) 2015-2024 ${application.title} (https://fineract.apache.org)${AnsiColor.BLACK} ${AnsiStyle.FAINT}${AnsiColor.WHITE}Powered by Spring Boot ${spring-boot.version}${AnsiColor.BLACK} diff --git a/fineract-provider/src/test/java/org/apache/fineract/TestConfiguration.java b/fineract-provider/src/test/java/org/apache/fineract/TestConfiguration.java index 8eb9a36dc..9c8d14e8b 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/TestConfiguration.java +++ b/fineract-provider/src/test/java/org/apache/fineract/TestConfiguration.java @@ -25,6 +25,7 @@ import com.zaxxer.hikari.HikariDataSource; import java.util.List; import javax.sql.DataSource; import liquibase.change.custom.CustomTaskChange; +import okhttp3.OkHttpClient; import org.apache.fineract.infrastructure.core.config.FineractProperties; import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant; import org.apache.fineract.infrastructure.core.service.database.DatabaseIndependentQueryService; @@ -188,4 +189,10 @@ public class TestConfiguration { public JobOperator jobOperator() { return mock(JobOperator.class, RETURNS_MOCKS); } + + @Primary + @Bean + public OkHttpClient okHttpClient() { + return mock(OkHttpClient.class, RETURNS_MOCKS); + } } diff --git a/fineract-provider/src/test/java/org/apache/fineract/cob/COBBusinessStepServiceStepDefinitions.java b/fineract-provider/src/test/java/org/apache/fineract/cob/COBBusinessStepServiceStepDefinitions.java index c020be0cb..7b3ca4899 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/cob/COBBusinessStepServiceStepDefinitions.java +++ b/fineract-provider/src/test/java/org/apache/fineract/cob/COBBusinessStepServiceStepDefinitions.java @@ -26,10 +26,9 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import com.google.common.base.Splitter; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import io.cucumber.java8.En; -import java.math.BigDecimal; import java.util.Collections; -import java.util.HashMap; import java.util.List; import java.util.Set; import java.util.TreeMap; @@ -44,12 +43,12 @@ import org.apache.fineract.infrastructure.core.domain.AbstractAuditableCustom; import org.apache.fineract.infrastructure.core.domain.ActionContext; import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil; import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService; -import org.apache.fineract.mix.data.MixTaxonomyData; import org.mockito.Mockito; import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.context.ApplicationContext; +@SuppressFBWarnings(value = "RV_EXCEPTION_NOT_THROWN", justification = "False positive") public class COBBusinessStepServiceStepDefinitions implements En { private ApplicationContext applicationContext = mock(ApplicationContext.class); @@ -68,10 +67,6 @@ public class COBBusinessStepServiceStepDefinitions implements En { private AbstractAuditableCustom outputItem = mock(AbstractAuditableCustom.class); private AbstractAuditableCustom resultItem; - - private HashMap data = new HashMap<>(); - - private String result; private Class clazz; private String jobName; private BatchBusinessStep batchBusinessStep = mock(BatchBusinessStep.class); diff --git a/fineract-provider/src/test/java/org/apache/fineract/cob/common/InitialisationTaskletStepDefinitions.java b/fineract-provider/src/test/java/org/apache/fineract/cob/common/InitialisationTaskletStepDefinitions.java index 80f831f41..17df55f23 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/cob/common/InitialisationTaskletStepDefinitions.java +++ b/fineract-provider/src/test/java/org/apache/fineract/cob/common/InitialisationTaskletStepDefinitions.java @@ -23,6 +23,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.mock; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import io.cucumber.java8.En; import java.time.LocalDate; import java.time.ZoneId; @@ -41,6 +42,7 @@ import org.springframework.batch.core.scope.context.StepContext; import org.springframework.batch.repeat.RepeatStatus; import org.springframework.security.core.context.SecurityContextHolder; +@SuppressFBWarnings(value = "RV_EXCEPTION_NOT_THROWN", justification = "False positive") public class InitialisationTaskletStepDefinitions implements En { private static final LocalDate TODAY = LocalDate.now(ZoneId.systemDefault()); diff --git a/fineract-provider/src/test/java/org/apache/fineract/cob/loan/ApplyLoanLockTaskletStepDefinitions.java b/fineract-provider/src/test/java/org/apache/fineract/cob/loan/ApplyLoanLockTaskletStepDefinitions.java index ead01296a..7f4393e05 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/cob/loan/ApplyLoanLockTaskletStepDefinitions.java +++ b/fineract-provider/src/test/java/org/apache/fineract/cob/loan/ApplyLoanLockTaskletStepDefinitions.java @@ -26,6 +26,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import io.cucumber.java8.En; import java.time.LocalDate; import java.time.ZoneId; @@ -50,6 +51,7 @@ import org.springframework.batch.repeat.RepeatStatus; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.support.TransactionTemplate; +@SuppressFBWarnings(value = "RV_EXCEPTION_NOT_THROWN", justification = "False positive") public class ApplyLoanLockTaskletStepDefinitions implements En { ArgumentCaptor valueCaptor = ArgumentCaptor.forClass(List.class); diff --git a/fineract-provider/src/test/java/org/apache/fineract/cob/loan/LoanItemProcessorStepDefinitions.java b/fineract-provider/src/test/java/org/apache/fineract/cob/loan/LoanItemProcessorStepDefinitions.java index 15d0f31f3..a5b19982a 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/cob/loan/LoanItemProcessorStepDefinitions.java +++ b/fineract-provider/src/test/java/org/apache/fineract/cob/loan/LoanItemProcessorStepDefinitions.java @@ -25,6 +25,7 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.mock; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import io.cucumber.java8.En; import java.time.LocalDate; import java.time.ZoneId; @@ -36,6 +37,7 @@ import org.springframework.batch.core.JobExecution; import org.springframework.batch.core.StepExecution; import org.springframework.batch.item.ExecutionContext; +@SuppressFBWarnings(value = "RV_EXCEPTION_NOT_THROWN", justification = "False positive") public class LoanItemProcessorStepDefinitions implements En { private COBBusinessStepService cobBusinessStepService = mock(COBBusinessStepService.class); diff --git a/fineract-provider/src/test/java/org/apache/fineract/cob/loan/LoanItemReaderStepDefinitions.java b/fineract-provider/src/test/java/org/apache/fineract/cob/loan/LoanItemReaderStepDefinitions.java index 562d4b9a8..26d2be8b4 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/cob/loan/LoanItemReaderStepDefinitions.java +++ b/fineract-provider/src/test/java/org/apache/fineract/cob/loan/LoanItemReaderStepDefinitions.java @@ -26,6 +26,7 @@ import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.mock; import com.google.common.base.Splitter; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import io.cucumber.java8.En; import java.time.LocalDate; import java.time.ZoneId; @@ -47,6 +48,7 @@ import org.springframework.batch.core.JobExecution; import org.springframework.batch.core.StepExecution; import org.springframework.batch.item.ExecutionContext; +@SuppressFBWarnings(value = "RV_EXCEPTION_NOT_THROWN", justification = "False positive") public class LoanItemReaderStepDefinitions implements En { private LoanRepository loanRepository = mock(LoanRepository.class); diff --git a/fineract-provider/src/test/java/org/apache/fineract/cob/service/COBBulkEventConfigurationTest.java b/fineract-provider/src/test/java/org/apache/fineract/cob/service/COBBulkEventConfigurationTest.java index 31c7cb91d..055009be1 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/cob/service/COBBulkEventConfigurationTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/cob/service/COBBulkEventConfigurationTest.java @@ -27,6 +27,7 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.time.LocalDate; import java.time.ZoneId; import java.util.HashMap; @@ -54,6 +55,7 @@ import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.context.ApplicationContext; @ExtendWith(MockitoExtension.class) +@SuppressFBWarnings(value = "RV_EXCEPTION_NOT_THROWN", justification = "False positive") public class COBBulkEventConfigurationTest { @Mock diff --git a/fineract-provider/src/test/java/org/apache/fineract/cob/service/InlineLoanCOBExecutorServiceImplTest.java b/fineract-provider/src/test/java/org/apache/fineract/cob/service/InlineLoanCOBExecutorServiceImplTest.java index 3324bb8d4..af2cec602 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/cob/service/InlineLoanCOBExecutorServiceImplTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/cob/service/InlineLoanCOBExecutorServiceImplTest.java @@ -27,6 +27,7 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.time.LocalDate; @@ -52,6 +53,7 @@ import org.springframework.transaction.support.TransactionTemplate; @ExtendWith(MockitoExtension.class) @MockitoSettings(strictness = Strictness.LENIENT) +@SuppressFBWarnings(value = "RV_EXCEPTION_NOT_THROWN", justification = "False positive") class InlineLoanCOBExecutorServiceImplTest { @InjectMocks diff --git a/fineract-provider/src/test/java/org/apache/fineract/commands/provider/CommandHandlerExceptionStepDefinitions.java b/fineract-provider/src/test/java/org/apache/fineract/commands/provider/CommandHandlerExceptionStepDefinitions.java index c5d84d168..174004442 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/commands/provider/CommandHandlerExceptionStepDefinitions.java +++ b/fineract-provider/src/test/java/org/apache/fineract/commands/provider/CommandHandlerExceptionStepDefinitions.java @@ -20,10 +20,12 @@ package org.apache.fineract.commands.provider; import static org.junit.jupiter.api.Assertions.assertThrows; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import io.cucumber.java8.En; import org.apache.fineract.commands.exception.UnsupportedCommandException; import org.springframework.beans.factory.annotation.Autowired; +@SuppressFBWarnings(value = "RV_EXCEPTION_NOT_THROWN", justification = "False positive") public class CommandHandlerExceptionStepDefinitions implements En { @Autowired diff --git a/fineract-provider/src/test/java/org/apache/fineract/commands/service/CommandSourceServiceTest.java b/fineract-provider/src/test/java/org/apache/fineract/commands/service/CommandSourceServiceTest.java index 6cf486bde..04c30e483 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/commands/service/CommandSourceServiceTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/commands/service/CommandSourceServiceTest.java @@ -21,6 +21,7 @@ package org.apache.fineract.commands.service; import static org.apache.fineract.commands.domain.CommandProcessingResultType.UNDER_PROCESSING; import static org.mockito.ArgumentMatchers.any; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.time.ZoneId; import java.util.Optional; import org.apache.fineract.batch.exception.ErrorInfo; @@ -44,6 +45,7 @@ import org.mockito.MockedStatic; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; +@SuppressFBWarnings(value = "RV_EXCEPTION_NOT_THROWN", justification = "False positive") public class CommandSourceServiceTest { @Mock diff --git a/fineract-provider/src/test/java/org/apache/fineract/commands/service/SynchronousCommandProcessingServiceTest.java b/fineract-provider/src/test/java/org/apache/fineract/commands/service/SynchronousCommandProcessingServiceTest.java index 1c9e0249d..9fdcf694d 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/commands/service/SynchronousCommandProcessingServiceTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/commands/service/SynchronousCommandProcessingServiceTest.java @@ -22,6 +22,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import jakarta.servlet.http.HttpServletRequest; import java.util.Map; import org.apache.fineract.commands.domain.CommandProcessingResultType; @@ -48,6 +49,7 @@ import org.springframework.context.ApplicationContext; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; +@SuppressFBWarnings(value = "RV_EXCEPTION_NOT_THROWN", justification = "False positive") public class SynchronousCommandProcessingServiceTest { @Mock diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/businessdate/service/BusinessDateWritePlatformServiceTest.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/businessdate/service/BusinessDateWritePlatformServiceTest.java index a73f7d613..9fdcb129d 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/businessdate/service/BusinessDateWritePlatformServiceTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/businessdate/service/BusinessDateWritePlatformServiceTest.java @@ -25,6 +25,7 @@ import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.time.LocalDate; import java.time.ZoneId; import java.util.Optional; @@ -55,6 +56,7 @@ import org.mockito.quality.Strictness; @ExtendWith(MockitoExtension.class) @MockitoSettings(strictness = Strictness.LENIENT) +@SuppressFBWarnings(value = "RV_EXCEPTION_NOT_THROWN", justification = "False positive") public class BusinessDateWritePlatformServiceTest { @InjectMocks diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/LiquibaseStepDefinitions.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/LiquibaseStepDefinitions.java index 0e72639e0..bec504a26 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/LiquibaseStepDefinitions.java +++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/LiquibaseStepDefinitions.java @@ -105,7 +105,7 @@ public class LiquibaseStepDefinitions implements En { }); Then("The database migration did not do anything", () -> { - verify(databaseStateVerifier).isLiquibaseDisabled(); + assertThat(verify(databaseStateVerifier).isLiquibaseDisabled()).isFalse(); verifyNoMoreInteractions(databaseStateVerifier); verifyNoInteractions(tenantDetailsService, tenantStoreDataSource, liquibaseFactory, tenantDataSourceFactory); }); diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/MultiExceptionStepDefinitions.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/MultiExceptionStepDefinitions.java index 86539a49b..b4fce117f 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/MultiExceptionStepDefinitions.java +++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/MultiExceptionStepDefinitions.java @@ -20,18 +20,18 @@ package org.apache.fineract.infrastructure.core; import static org.junit.jupiter.api.Assertions.assertThrows; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import io.cucumber.java8.En; import java.util.ArrayList; import java.util.List; import org.apache.commons.lang3.StringUtils; import org.apache.fineract.infrastructure.core.exception.MultiException; +@SuppressFBWarnings(value = "RV_EXCEPTION_NOT_THROWN", justification = "False positive") public class MultiExceptionStepDefinitions implements En { private List exceptions = new ArrayList<>(); - private MultiException multiException; - public MultiExceptionStepDefinitions() { Given("/^A multi exception with exceptions (.*) and (.*)$/", (String exception1, String exception2) -> { if (!StringUtils.isBlank(exception1)) { diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/creditbureau/service/ThitsaWorksCreditBureauIntegrationWritePlatformServiceImplTest.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/creditbureau/service/ThitsaWorksCreditBureauIntegrationWritePlatformServiceImplTest.java index 47fb2e845..26e545af6 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/creditbureau/service/ThitsaWorksCreditBureauIntegrationWritePlatformServiceImplTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/creditbureau/service/ThitsaWorksCreditBureauIntegrationWritePlatformServiceImplTest.java @@ -32,8 +32,10 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.gson.JsonParser; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.time.ZoneId; @@ -71,25 +73,26 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.Spy; +@SuppressFBWarnings(value = "RV_EXCEPTION_NOT_THROWN", justification = "False positive") public class ThitsaWorksCreditBureauIntegrationWritePlatformServiceImplTest { @Spy private FromJsonHelper fromJsonHelper = new FromJsonHelper(); - @Spy - private CreditBureauTokenCommandFromApiJsonDeserializer fromApiJsonDeserializer = new CreditBureauTokenCommandFromApiJsonDeserializer( - fromJsonHelper); @Mock private OkHttpClient okHttpClient; @Mock private CreditBureauConfigurationRepositoryWrapper configurationRepositoryWrapper; + @Mock + private TokenRepositoryWrapper tokenRepositoryWrapper; + @Mock private PlatformSecurityContext platformSecurityContext; @Mock - private TokenRepositoryWrapper tokenRepositoryWrapper; + private CreditBureauTokenCommandFromApiJsonDeserializer fromApiJsonDeserializer; private final ObjectMapper mapper = new ObjectMapper(); @@ -261,7 +264,7 @@ public class ThitsaWorksCreditBureauIntegrationWritePlatformServiceImplTest { String jsonResponse = createResponseObjectArrayData(() -> "UPLOADED", data -> data); Path temp = Files.createTempFile("upload_test" + System.currentTimeMillis(), ".data"); - Files.writeString(temp, "test"); + Files.writeString(temp, "test", StandardCharsets.UTF_8); mockOkHttpCall(request -> { assertEquals(request.header("Authorization"), "Bearer AccessToken"); @@ -474,7 +477,7 @@ public class ThitsaWorksCreditBureauIntegrationWritePlatformServiceImplTest { String jsonResponse = createResponseObjectArrayData(() -> "ADD_CREDIT_RESPONSE", data -> data); Path temp = Files.createTempFile("add_credit_report" + System.currentTimeMillis(), ".data"); - Files.writeString(temp, "test"); + Files.writeString(temp, "test", StandardCharsets.UTF_8); mockOkHttpCall(request -> { if (request.url().host().equals("addcredit.report.url")) { diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImplTest.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImplTest.java index f38920ce8..b8bd9476c 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImplTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImplTest.java @@ -29,6 +29,7 @@ import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.Mockito.when; import com.google.gson.JsonObject; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.util.List; import java.util.stream.Stream; import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException; @@ -49,6 +50,7 @@ import org.mockito.MockitoAnnotations; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.support.rowset.SqlRowSet; +@SuppressFBWarnings(value = "RV_EXCEPTION_NOT_THROWN", justification = "False positive") public class ReadWriteNonCoreDataServiceImplTest { @Mock diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/producer/kafka/KafkaExternalEventProducerTest.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/producer/kafka/KafkaExternalEventProducerTest.java index 21ab34de8..a76ba420d 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/producer/kafka/KafkaExternalEventProducerTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/producer/kafka/KafkaExternalEventProducerTest.java @@ -20,6 +20,7 @@ package org.apache.fineract.infrastructure.event.external.producer.kafka; import static org.mockito.Mockito.times; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.nio.charset.Charset; import java.util.List; import java.util.Map; @@ -36,6 +37,7 @@ import org.springframework.kafka.core.KafkaTemplate; import org.springframework.kafka.support.SendResult; @ExtendWith(MockitoExtension.class) +@SuppressFBWarnings(value = "RV_EXCEPTION_NOT_THROWN", justification = "False positive") class KafkaExternalEventProducerTest { public static final String TOPIC_NAME = "unit-test"; diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/CustomExternalEventConfigurationRepositoryImplTest.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/CustomExternalEventConfigurationRepositoryImplTest.java index 1793ac928..ed708f144 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/CustomExternalEventConfigurationRepositoryImplTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/CustomExternalEventConfigurationRepositoryImplTest.java @@ -23,6 +23,7 @@ import static org.hamcrest.Matchers.equalTo; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.Mockito.when; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import jakarta.persistence.EntityManager; import org.apache.fineract.infrastructure.event.external.exception.ExternalEventConfigurationNotFoundException; import org.apache.fineract.infrastructure.event.external.repository.CustomExternalEventConfigurationRepositoryImpl; @@ -35,6 +36,7 @@ import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; @ExtendWith(MockitoExtension.class) +@SuppressFBWarnings(value = "RV_EXCEPTION_NOT_THROWN", justification = "False positive") public class CustomExternalEventConfigurationRepositoryImplTest { @Mock diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanRepaymentBusinessEventSerializerTest.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanRepaymentBusinessEventSerializerTest.java index 6519ea604..be9215866 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanRepaymentBusinessEventSerializerTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanRepaymentBusinessEventSerializerTest.java @@ -53,7 +53,6 @@ import org.apache.fineract.portfolio.loanaccount.domain.Loan; import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment; import org.apache.fineract.portfolio.loanaccount.domain.LoanSummary; import org.apache.fineract.portfolio.loanaccount.service.LoanCalculateRepaymentPastDueService; -import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -153,7 +152,6 @@ public class LoanRepaymentBusinessEventSerializerTest { LocalDate loanInstallmentRepaymentDueDate = DateUtils.getBusinessLocalDate().plusDays(1); Loan loanForProcessing = Mockito.mock(Loan.class); - LoanProduct loanProduct = Mockito.mock(LoanProduct.class); LoanSummary loanSummary = Mockito.mock(LoanSummary.class); MonetaryCurrency loanCurrency = Mockito.mock(MonetaryCurrency.class); diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/jobs/filter/LoanCOBApiFilterTest.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/jobs/filter/LoanCOBApiFilterTest.java index f99f300c0..f1597f27f 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/jobs/filter/LoanCOBApiFilterTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/jobs/filter/LoanCOBApiFilterTest.java @@ -53,7 +53,6 @@ import org.apache.fineract.portfolio.loanaccount.domain.GLIMAccountInfoRepositor import org.apache.fineract.portfolio.loanaccount.domain.GroupLoanIndividualMonitoringAccount; import org.apache.fineract.portfolio.loanaccount.domain.Loan; import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository; -import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequest; import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequestRepository; import org.apache.fineract.useradministration.domain.AppUser; import org.apache.http.HttpStatus; @@ -254,7 +253,6 @@ class LoanCOBApiFilterTest { given(loanAccountLockService.isLoanHardLocked(2L)).willReturn(false); given(fineractProperties.getQuery()).willReturn(fineractQueryProperties); given(fineractQueryProperties.getInClauseParameterSizeLimit()).willReturn(65000); - LoanRescheduleRequest rescheduleRequest = mock(LoanRescheduleRequest.class); given(loanRescheduleRequestRepository.getLoanIdByRescheduleRequestId(resourceId)).willReturn(Optional.of(2L)); given(context.authenticatedUser()).willReturn(appUser); diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/security/utils/SQLInjectionValidatorTest.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/security/utils/SQLInjectionValidatorTest.java index a76e2ee07..cda6583ed 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/security/utils/SQLInjectionValidatorTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/security/utils/SQLInjectionValidatorTest.java @@ -18,10 +18,12 @@ */ package org.apache.fineract.infrastructure.security.utils; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.util.Arrays; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +@SuppressFBWarnings(value = "RV_EXCEPTION_NOT_THROWN", justification = "False positive") public class SQLInjectionValidatorTest { private static final String[] DDL_COMMANDS = { "create", "drop", "alter", "truncate", "comment", "sleep" }; diff --git a/fineract-provider/src/test/java/org/apache/fineract/investor/event/EnricherTest.java b/fineract-provider/src/test/java/org/apache/fineract/investor/event/EnricherTest.java index 64a49561b..8e11b5e0a 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/investor/event/EnricherTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/investor/event/EnricherTest.java @@ -53,16 +53,16 @@ import org.mockito.junit.jupiter.MockitoExtension; @ExtendWith(MockitoExtension.class) public class EnricherTest { - private final LocalDate actualDate = LocalDate.now(ZoneId.systemDefault()); + private static final LocalDate ACTUAL_DATE = LocalDate.now(ZoneId.systemDefault()); - private final String purchasePriceRatio = "100.123"; - private final String settlementDate = DateTimeFormatter.ISO_LOCAL_DATE.format(LocalDate.now(ZoneId.systemDefault())); + private static final String PURCHASE_PRICE_RATIO = "100.123"; + private static final String SETTLEMENT_DATE = DateTimeFormatter.ISO_LOCAL_DATE.format(LocalDate.now(ZoneId.systemDefault())); @BeforeEach public void setUp() { ThreadLocalContextUtil.setTenant(new FineractPlatformTenant(1L, "default", "Default", "Asia/Kolkata", null)); ThreadLocalContextUtil.setActionContext(ActionContext.DEFAULT); - ThreadLocalContextUtil.setBusinessDates(new HashMap<>(Map.of(BusinessDateType.BUSINESS_DATE, actualDate))); + ThreadLocalContextUtil.setBusinessDates(new HashMap<>(Map.of(BusinessDateType.BUSINESS_DATE, ACTUAL_DATE))); } @@ -73,8 +73,8 @@ public class EnricherTest { doAnswer(a -> { LoanAccountDataV1 data = a.getArgument(0, LoanAccountDataV1.class); data.setExternalOwnerId("1"); - data.setSettlementDate(settlementDate); - data.setPurchasePriceRatio(purchasePriceRatio); + data.setSettlementDate(SETTLEMENT_DATE); + data.setPurchasePriceRatio(PURCHASE_PRICE_RATIO); return null; }).when(loanAccountDataV1Enricher).enrich(any(LoanAccountDataV1.class)); @@ -86,8 +86,8 @@ public class EnricherTest { verify(loanAccountDataV1Enricher, times(1)).enrich(any(LoanAccountDataV1.class)); assertEquals("1", original.getExternalOwnerId()); - assertEquals(settlementDate, original.getSettlementDate()); - assertEquals(purchasePriceRatio, original.getPurchasePriceRatio()); + assertEquals(SETTLEMENT_DATE, original.getSettlementDate()); + assertEquals(PURCHASE_PRICE_RATIO, original.getPurchasePriceRatio()); } @Test @@ -143,8 +143,8 @@ public class EnricherTest { doAnswer(a -> { LoanAccountDataV1 data = a.getArgument(0, LoanAccountDataV1.class); data.setExternalOwnerId("1"); - data.setSettlementDate(settlementDate); - data.setPurchasePriceRatio(purchasePriceRatio); + data.setSettlementDate(SETTLEMENT_DATE); + data.setPurchasePriceRatio(PURCHASE_PRICE_RATIO); return null; }).when(loanAccountDataV1Enricher).enrich(any(LoanAccountDataV1.class)); @@ -174,8 +174,8 @@ public class EnricherTest { verify(loanTransactionDataV1Enricher, times(1)).isDataTypeSupported(any()); assertEquals("1", data.getExternalOwnerId()); - assertEquals(settlementDate, data.getSettlementDate()); - assertEquals(purchasePriceRatio, data.getPurchasePriceRatio()); + assertEquals(SETTLEMENT_DATE, data.getSettlementDate()); + assertEquals(PURCHASE_PRICE_RATIO, data.getPurchasePriceRatio()); } diff --git a/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/service/ReplayedTransactionBusinessEventServiceIntegrationTest.java b/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/service/ReplayedTransactionBusinessEventServiceIntegrationTest.java index 824f22c15..951704180 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/service/ReplayedTransactionBusinessEventServiceIntegrationTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/service/ReplayedTransactionBusinessEventServiceIntegrationTest.java @@ -23,6 +23,7 @@ import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.verify; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.util.Optional; import org.apache.fineract.infrastructure.event.business.domain.loan.LoanAdjustTransactionBusinessEvent; import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService; @@ -37,6 +38,7 @@ import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; @ExtendWith(MockitoExtension.class) +@SuppressFBWarnings(value = "RV_EXCEPTION_NOT_THROWN", justification = "False positive") class ReplayedTransactionBusinessEventServiceIntegrationTest { @Mock diff --git a/fineract-war/setenv.sh b/fineract-war/setenv.sh index 5d69b5aba..2d48674e5 100644 --- a/fineract-war/setenv.sh +++ b/fineract-war/setenv.sh @@ -53,3 +53,4 @@ export FINERACT_DEFAULT_TENANTDB_TIMEZONE="Asia/Kolkata" export FINERACT_DEFAULT_TENANTDB_IDENTIFIER="default" export FINERACT_DEFAULT_TENANTDB_NAME="fineract_default" export FINERACT_DEFAULT_TENANTDB_DESCRIPTION="Default Demo Tenant" +export FINERACT_INSECURE_HTTP_CLIENT="true" diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 249e5832f..7f93135c4 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index e411586a5..eed8d3ce1 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip +networkTimeout=100000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index a69d9cb6c..1aa94a426 100755 --- a/gradlew +++ b/gradlew @@ -55,7 +55,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -80,13 +80,11 @@ do esac done -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -APP_NAME="Gradle" +# This is normally unused +# shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -133,22 +131,29 @@ location of your Java installation." fi else JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -193,11 +198,15 @@ if "$cygwin" || "$msys" ; then done fi -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ diff --git a/gradlew.bat b/gradlew.bat index 53a6b238d..6689b85be 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -26,6 +26,7 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% diff --git a/integration-tests/dependencies.gradle b/integration-tests/dependencies.gradle index 206bd6a7a..460d5c33f 100644 --- a/integration-tests/dependencies.gradle +++ b/integration-tests/dependencies.gradle @@ -20,7 +20,7 @@ dependencies { // testCompile dependencies are ONLY used in src/test, not src/main. // Do NOT repeat dependencies which are ALREADY in implementation or runtimeOnly! // - tomcat 'org.apache.tomcat:tomcat:10.1.16@zip' + tomcat 'org.apache.tomcat:tomcat:10.1.17@zip' testImplementation( files("$rootDir/fineract-provider/build/classes/java/main/"), project(path: ':fineract-core', configuration: 'runtimeElements'), project(path: ':fineract-investor', configuration: 'runtimeElements'), diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanIntegrationTest.java index b0287e94a..3618bd14d 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanIntegrationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanIntegrationTest.java @@ -28,6 +28,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import com.google.gson.Gson; import com.google.gson.JsonObject; import com.google.gson.JsonParser; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import io.restassured.builder.RequestSpecBuilder; import io.restassured.builder.ResponseSpecBuilder; import io.restassured.http.ContentType; @@ -127,6 +128,7 @@ import org.slf4j.LoggerFactory; */ @SuppressWarnings({ "rawtypes", "unchecked" }) @ExtendWith(LoanTestLifecycleExtension.class) +@SuppressFBWarnings(value = "RV_EXCEPTION_NOT_THROWN", justification = "False positive") public class ClientLoanIntegrationTest { static { diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/StaffTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/StaffTest.java index eb83bd55f..cbbb19dd0 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/StaffTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/StaffTest.java @@ -19,6 +19,7 @@ package org.apache.fineract.integrationtests; import com.google.gson.Gson; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import io.restassured.builder.RequestSpecBuilder; import io.restassured.builder.ResponseSpecBuilder; import io.restassured.http.ContentType; @@ -35,6 +36,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @Deprecated // TODO move this into new org.apache.fineract.integrationtests.client.StaffTest +@SuppressFBWarnings(value = "RV_EXCEPTION_NOT_THROWN", justification = "False positive") public class StaffTest { private RequestSpecification requestSpec; diff --git a/kubernetes/fineractmysql-deployment.yml b/kubernetes/fineractmysql-deployment.yml index f4c670920..582e3d200 100644 --- a/kubernetes/fineractmysql-deployment.yml +++ b/kubernetes/fineractmysql-deployment.yml @@ -86,7 +86,7 @@ spec: tier: fineractmysql spec: containers: - - image: mariadb:10.9 + - image: mariadb:11.2 name: mysql resources: requests: diff --git a/oauth2-tests/dependencies.gradle b/oauth2-tests/dependencies.gradle index d05ea6642..d1041fe30 100644 --- a/oauth2-tests/dependencies.gradle +++ b/oauth2-tests/dependencies.gradle @@ -20,7 +20,7 @@ dependencies { // testCompile dependencies are ONLY used in src/test, not src/main. // Do NOT repeat dependencies which are ALREADY in implementation or runtimeOnly! // - tomcat 'org.apache.tomcat:tomcat:10.1.16@zip' + tomcat 'org.apache.tomcat:tomcat:10.1.17@zip' testImplementation( files("$rootDir/fineract-provider/build/classes/java/main/"), project(path: ':fineract-provider', configuration: 'runtimeElements'), 'org.junit.jupiter:junit-jupiter-api', diff --git a/oauth2-tests/src/test/java/org/apache/fineract/oauth2tests/OAuth2AuthenticationTest.java b/oauth2-tests/src/test/java/org/apache/fineract/oauth2tests/OAuth2AuthenticationTest.java index 52132dc38..391ba7e03 100644 --- a/oauth2-tests/src/test/java/org/apache/fineract/oauth2tests/OAuth2AuthenticationTest.java +++ b/oauth2-tests/src/test/java/org/apache/fineract/oauth2tests/OAuth2AuthenticationTest.java @@ -39,7 +39,6 @@ import org.junit.jupiter.api.Test; public class OAuth2AuthenticationTest { private ResponseSpecification responseSpec; - private ResponseSpecification responseSpec403; private ResponseSpecification responseSpec401; private RequestSpecification requestSpec; private RequestSpecification requestFormSpec; @@ -61,7 +60,6 @@ public class OAuth2AuthenticationTest { this.requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build(); this.requestFormSpec = new RequestSpecBuilder().setContentType(ContentType.URLENC).build(); this.responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build(); - this.responseSpec403 = new ResponseSpecBuilder().expectStatusCode(403).build(); this.responseSpec401 = new ResponseSpecBuilder().expectStatusCode(401).build(); } diff --git a/settings.gradle b/settings.gradle index 871f5436a..c33ea27a8 100644 --- a/settings.gradle +++ b/settings.gradle @@ -18,8 +18,8 @@ */ plugins { - id 'com.gradle.enterprise' version '3.15.1' - id 'com.gradle.common-custom-user-data-gradle-plugin' version '1.12' + id 'com.gradle.enterprise' version '3.16.1' + id 'com.gradle.common-custom-user-data-gradle-plugin' version '1.12.1' } def isCI = System.getenv('JENKINS_URL') != null diff --git a/twofactor-tests/dependencies.gradle b/twofactor-tests/dependencies.gradle index 9e0a6e12a..40c7f68a8 100644 --- a/twofactor-tests/dependencies.gradle +++ b/twofactor-tests/dependencies.gradle @@ -20,7 +20,7 @@ dependencies { // testCompile dependencies are ONLY used in src/test, not src/main. // Do NOT repeat dependencies which are ALREADY in implementation or runtimeOnly! // - tomcat 'org.apache.tomcat:tomcat:10.1.16@zip' + tomcat 'org.apache.tomcat:tomcat:10.1.17@zip' testImplementation( files("$rootDir/fineract-provider/build/classes/java/main/"), project(path: ':fineract-provider', configuration: 'runtimeElements'), 'org.junit.jupiter:junit-jupiter-api',