diff --git a/.DS_Store b/.DS_Store
deleted file mode 100644
index 3fa89eb1..00000000
Binary files a/.DS_Store and /dev/null differ
diff --git a/.circleci/config.yml b/.circleci/config.yml
new file mode 100644
index 00000000..810e7718
--- /dev/null
+++ b/.circleci/config.yml
@@ -0,0 +1,186 @@
+version: 2.1
+orbs:
+ docker-buildx: devarsh/docker-buildx-orb@0.1.1
+executors:
+ docker-executor:
+ docker:
+ - image: eclipse-temurin:17-jdk
+jobs:
+ build_and_push_tag_image:
+ executor: docker-executor
+ environment:
+ JVM_OPTS: -Xmx512m
+ TERM: dumb
+ steps:
+ - checkout
+ - setup_remote_docker:
+ version: 20.10.24
+ - run:
+ name: Set Lowercase Docker Image Vars
+ # Using tr for POSIX compatibility, could use ${VAR,,} with Bash 4+
+ command: |
+ echo "export DOCKER_ORG_LOWER=$(echo $CIRCLE_PROJECT_USERNAME | tr '[:upper:]' '[:lower:]')" >> $BASH_ENV
+ echo "export DOCKER_REPO_LOWER=$(echo $CIRCLE_PROJECT_REPONAME | tr '[:upper:]' '[:lower:]')" >> $BASH_ENV
+ echo "Using Docker Namespace: $DOCKER_ORG_LOWER"
+ echo "Using Docker Repository: $DOCKER_REPO_LOWER"
+ - run:
+ name: Install Docker CLI
+ command: |
+ apt-get update
+ apt-get install -y curl ca-certificates gnupg
+ install -m 0755 -d /etc/apt/keyrings
+ curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
+ chmod a+r /etc/apt/keyrings/docker.asc
+ echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian bullseye stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
+ apt-get update
+ apt-cache madison docker-ce-cli | grep 20.10
+ apt-get install -y docker-ce-cli=5:20.10.24~3-0~debian-bullseye
+ - docker-buildx/install
+ # - run:
+ # name: Check if Docker image tag exists
+ # command: |
+ # IMAGE_TAG=$CIRCLE_TAG
+ # # Using lowercase variables defined above
+ # IMAGE_NAME="$DOCKER_ORG_LOWER/$DOCKER_REPO_LOWER"
+ # echo "Checking for Docker image: $IMAGE_NAME:$IMAGE_TAG"
+ # # Ensure DOCKERHUB_USERNAME and DOCKERHUB_PASSWORD are set in your CircleCI Context or Project Environment Variables
+ # if curl -s -f -u "$DOCKERHUB_USERNAME":"$DOCKERHUB_PASSWORD" "https://hub.docker.com/v2/repositories/$IMAGE_NAME/tags/$IMAGE_TAG" > /dev/null; then
+ # echo "Skipping the build and push as the tag $IMAGE_TAG already exists in Docker Hub for image $IMAGE_NAME."
+ # circleci-agent step halt
+ # else
+ # echo "Tag $IMAGE_TAG does not exist for image $IMAGE_NAME. Proceeding with build."
+ # fi
+ - run:
+ name: Build Application
+ command: ./gradlew bootJar
+ - docker-buildx/build-and-push:
+ # Using lowercase variables defined above
+ image-name: "$DOCKER_ORG_LOWER/$DOCKER_REPO_LOWER"
+ tag: "$CIRCLE_TAG"
+ # Add dockerhub credentials if needed
+ # dockerhub-username: "$DOCKERHUB_USERNAME"
+ # dockerhub-password: "$DOCKERHUB_PASSWORD"
+ build_and_push_branch_image:
+ executor: docker-executor
+ environment:
+ JVM_OPTS: -Xmx512m
+ TERM: dumb
+ steps:
+ - checkout
+ - setup_remote_docker:
+ version: 20.10.24
+ - run:
+ name: Set Lowercase Docker Image Vars
+ command: |
+ echo "export DOCKER_ORG_LOWER=$(echo $CIRCLE_PROJECT_USERNAME | tr '[:upper:]' '[:lower:]')" >> $BASH_ENV
+ echo "export DOCKER_REPO_LOWER=$(echo $CIRCLE_PROJECT_REPONAME | tr '[:upper:]' '[:lower:]')" >> $BASH_ENV
+ echo "Using Docker Namespace: $DOCKER_ORG_LOWER"
+ echo "Using Docker Repository: $DOCKER_REPO_LOWER"
+ - run:
+ name: Install Docker CLI
+ command: |
+ apt-get update
+ apt-get install -y curl ca-certificates gnupg
+ install -m 0755 -d /etc/apt/keyrings
+ curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
+ chmod a+r /etc/apt/keyrings/docker.asc
+ echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian bullseye stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
+ apt-get update
+ apt-cache madison docker-ce-cli | grep 20.10
+ apt-get install -y docker-ce-cli=5:20.10.24~3-0~debian-bullseye
+ - docker-buildx/install
+ - run:
+ name: Build Application
+ command: |
+ ./gradlew checkstyleMain
+ ./gradlew clean bootJar
+ - run:
+ name: Sanitize Branch Name
+ command: |
+ echo "export SANITIZED_BRANCH=$(echo $CIRCLE_BRANCH | sed 's/[^a-zA-Z0-9.-]/-/g' | tr '[:upper:]' '[:lower:]')" >> $BASH_ENV # Also ensure branch tag is lowercase
+ # First build and push with branch-latest tag
+ - docker-buildx/build-and-push:
+ image-name: "$DOCKER_ORG_LOWER/$DOCKER_REPO_LOWER"
+ tag: "${SANITIZED_BRANCH}-latest"
+ # Then build and push with branch-version tag
+ - docker-buildx/build-and-push:
+ image-name: "$DOCKER_ORG_LOWER/$DOCKER_REPO_LOWER"
+ tag: "${SANITIZED_BRANCH}"
+ # Add dockerhub credentials if needed
+ # dockerhub-username: "$DOCKERHUB_USERNAME"
+ # dockerhub-password: "$DOCKERHUB_PASSWORD"
+ build_and_push_latest_image:
+ executor: docker-executor
+ environment:
+ JVM_OPTS: -Xmx512m
+ TERM: dumb
+ steps:
+ - checkout
+ - setup_remote_docker:
+ version: 20.10.24
+ - run:
+ name: Set Lowercase Docker Image Vars
+ command: |
+ echo "export DOCKER_ORG_LOWER=$(echo $CIRCLE_PROJECT_USERNAME | tr '[:upper:]' '[:lower:]')" >> $BASH_ENV
+ echo "export DOCKER_REPO_LOWER=$(echo $CIRCLE_PROJECT_REPONAME | tr '[:upper:]' '[:lower:]')" >> $BASH_ENV
+ echo "Using Docker Namespace: $DOCKER_ORG_LOWER"
+ echo "Using Docker Repository: $DOCKER_REPO_LOWER"
+ - run:
+ name: Install Docker CLI
+ command: |
+ apt-get update
+ apt-get install -y curl ca-certificates gnupg
+ install -m 0755 -d /etc/apt/keyrings
+ curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
+ chmod a+r /etc/apt/keyrings/docker.asc
+ echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian bullseye stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
+ apt-get update
+ apt-cache madison docker-ce-cli | grep 20.10
+ apt-get install -y docker-ce-cli=5:20.10.24~3-0~debian-bullseye
+ - docker-buildx/install
+ - run:
+ name: Build Application
+ command: |
+ ./gradlew checkstyleMain
+ ./gradlew clean bootJar
+ - docker-buildx/build-and-push:
+ # Using lowercase variables defined above
+ image-name: "$DOCKER_ORG_LOWER/$DOCKER_REPO_LOWER"
+ tag: "latest"
+ # Add dockerhub credentials if needed
+ # dockerhub-username: "$DOCKERHUB_USERNAME"
+ # dockerhub-password: "$DOCKERHUB_PASSWORD"
+workflows:
+ version: 2
+ build-and-push-pipeline:
+ jobs:
+ # Build tags matching vX.Y.Z format
+ - build_and_push_tag_image:
+ filters:
+ tags:
+ only: /^v\d+\.\d+\.\d+$/
+ branches:
+ ignore: /.*/
+ context:
+ - DOCKER
+ # Build any branch commit (except tags)
+ - build_and_push_branch_image:
+ filters:
+ tags:
+ ignore: /.*/
+ branches:
+ only: /.*/
+ context:
+ - DOCKER
+ # Build 'latest' only when the branch image succeeds AND it's the main/master branch
+ - build_and_push_latest_image:
+ requires:
+ - build_and_push_branch_image
+ filters:
+ tags:
+ ignore: /.*/
+ branches:
+ only:
+ - main # Or your primary branch name like 'master'
+ context:
+ - DOCKER
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
new file mode 100644
index 00000000..bcf84d8d
--- /dev/null
+++ b/.github/pull_request_template.md
@@ -0,0 +1,22 @@
+## Description
+
+* PR title should have jira ticket enclosed in `[]`.
+Format: ``` [jira_ticket] description```
+ex: [phee-123] PR title.
+* Add a link to the Jira ticket.
+* Describe the changes made and why they were made.
+
+## Checklist
+
+Please make sure these boxes are checked before submitting your pull request - thanks!
+- [ ] Followed the PR title naming convention mentioned above.
+
+- [ ] Design related bullet points or design document link related to this PR added in the description above.
+
+- [ ] Updated corresponding Postman Collection or Api documentation for the changes in this PR.
+
+- [ ] Created/updated unit or integration tests for verifying the changes made.
+
+- [ ] Added required Swagger annotation and update API documentation with details of any API changes if applicable
+
+- [ ] Followed the naming conventions as given in https://docs.google.com/document/d/1Q4vaMSzrTxxh9TS0RILuNkSkYCxotuYk1Xe0CMIkkCU/edit?usp=sharing
diff --git a/.gitignore b/.gitignore
index 14cce966..3d34106d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -36,4 +36,8 @@ build/
.vscode/
.DS_Store
-/.mvn
\ No newline at end of file
+/.mvn
+# Certificate files (use K8s secrets instead)
+*.jks
+*.p12
+*.keystore
diff --git a/.mvn/wrapper/MavenWrapperDownloader.java b/.mvn/wrapper/MavenWrapperDownloader.java
deleted file mode 100644
index a45eb6ba..00000000
--- a/.mvn/wrapper/MavenWrapperDownloader.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright 2007-present the original author or authors.
- *
- * Licensed 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
- *
- * https://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.
- */
-
-import java.net.*;
-import java.io.*;
-import java.nio.channels.*;
-import java.util.Properties;
-
-public class MavenWrapperDownloader {
-
- private static final String WRAPPER_VERSION = "0.5.6";
- /**
- * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
- */
- private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
- + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
-
- /**
- * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
- * use instead of the default one.
- */
- private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
- ".mvn/wrapper/maven-wrapper.properties";
-
- /**
- * Path where the maven-wrapper.jar will be saved to.
- */
- private static final String MAVEN_WRAPPER_JAR_PATH =
- ".mvn/wrapper/maven-wrapper.jar";
-
- /**
- * Name of the property which should be used to override the default download url for the wrapper.
- */
- private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
-
- public static void main(String args[]) {
- System.out.println("- Downloader started");
- File baseDirectory = new File(args[0]);
- System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
-
- // If the maven-wrapper.properties exists, read it and check if it contains a custom
- // wrapperUrl parameter.
- File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
- String url = DEFAULT_DOWNLOAD_URL;
- if (mavenWrapperPropertyFile.exists()) {
- FileInputStream mavenWrapperPropertyFileInputStream = null;
- try {
- mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
- Properties mavenWrapperProperties = new Properties();
- mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
- url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
- } catch (IOException e) {
- System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
- } finally {
- try {
- if (mavenWrapperPropertyFileInputStream != null) {
- mavenWrapperPropertyFileInputStream.close();
- }
- } catch (IOException e) {
- // Ignore ...
- }
- }
- }
- System.out.println("- Downloading from: " + url);
-
- File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
- if (!outputFile.getParentFile().exists()) {
- if (!outputFile.getParentFile().mkdirs()) {
- System.out.println(
- "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
- }
- }
- System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
- try {
- downloadFileFromURL(url, outputFile);
- System.out.println("Done");
- System.exit(0);
- } catch (Throwable e) {
- System.out.println("- Error downloading");
- e.printStackTrace();
- System.exit(1);
- }
- }
-
- private static void downloadFileFromURL(String urlString, File destination) throws Exception {
- if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
- String username = System.getenv("MVNW_USERNAME");
- char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
- Authenticator.setDefault(new Authenticator() {
- @Override
- protected PasswordAuthentication getPasswordAuthentication() {
- return new PasswordAuthentication(username, password);
- }
- });
- }
- URL website = new URL(urlString);
- ReadableByteChannel rbc;
- rbc = Channels.newChannel(website.openStream());
- FileOutputStream fos = new FileOutputStream(destination);
- fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
- fos.close();
- rbc.close();
- }
-
-}
diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar
deleted file mode 100644
index 2cc7d4a5..00000000
Binary files a/.mvn/wrapper/maven-wrapper.jar and /dev/null differ
diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties
deleted file mode 100644
index ffdc10e5..00000000
--- a/.mvn/wrapper/maven-wrapper.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.1/apache-maven-3.8.1-bin.zip
-wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar
diff --git a/Dockerfile b/Dockerfile
index 7424e18f..2dccf6ed 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,5 +1,5 @@
-FROM openjdk:13
+FROM eclipse-temurin:17-jdk
EXPOSE 5000
-COPY target/*.jar .
+COPY build/libs/*.jar .
CMD java -jar *.jar
\ No newline at end of file
diff --git a/LICENSE.md b/LICENSE.md
new file mode 100644
index 00000000..a612ad98
--- /dev/null
+++ b/LICENSE.md
@@ -0,0 +1,373 @@
+Mozilla Public License Version 2.0
+==================================
+
+1. Definitions
+--------------
+
+1.1. "Contributor"
+ means each individual or legal entity that creates, contributes to
+ the creation of, or owns Covered Software.
+
+1.2. "Contributor Version"
+ means the combination of the Contributions of others (if any) used
+ by a Contributor and that particular Contributor's Contribution.
+
+1.3. "Contribution"
+ means Covered Software of a particular Contributor.
+
+1.4. "Covered Software"
+ means Source Code Form to which the initial Contributor has attached
+ the notice in Exhibit A, the Executable Form of such Source Code
+ Form, and Modifications of such Source Code Form, in each case
+ including portions thereof.
+
+1.5. "Incompatible With Secondary Licenses"
+ means
+
+ (a) that the initial Contributor has attached the notice described
+ in Exhibit B to the Covered Software; or
+
+ (b) that the Covered Software was made available under the terms of
+ version 1.1 or earlier of the License, but not also under the
+ terms of a Secondary License.
+
+1.6. "Executable Form"
+ means any form of the work other than Source Code Form.
+
+1.7. "Larger Work"
+ means a work that combines Covered Software with other material, in
+ a separate file or files, that is not Covered Software.
+
+1.8. "License"
+ means this document.
+
+1.9. "Licensable"
+ means having the right to grant, to the maximum extent possible,
+ whether at the time of the initial grant or subsequently, any and
+ all of the rights conveyed by this License.
+
+1.10. "Modifications"
+ means any of the following:
+
+ (a) any file in Source Code Form that results from an addition to,
+ deletion from, or modification of the contents of Covered
+ Software; or
+
+ (b) any new file in Source Code Form that contains any Covered
+ Software.
+
+1.11. "Patent Claims" of a Contributor
+ means any patent claim(s), including without limitation, method,
+ process, and apparatus claims, in any patent Licensable by such
+ Contributor that would be infringed, but for the grant of the
+ License, by the making, using, selling, offering for sale, having
+ made, import, or transfer of either its Contributions or its
+ Contributor Version.
+
+1.12. "Secondary License"
+ means either the GNU General Public License, Version 2.0, the GNU
+ Lesser General Public License, Version 2.1, the GNU Affero General
+ Public License, Version 3.0, or any later versions of those
+ licenses.
+
+1.13. "Source Code Form"
+ means the form of the work preferred for making modifications.
+
+1.14. "You" (or "Your")
+ means an individual or a legal entity exercising rights under this
+ License. For legal entities, "You" includes any entity that
+ controls, is controlled by, or is under common control with You. For
+ purposes of this definition, "control" means (a) the power, direct
+ or indirect, to cause the direction or management of such entity,
+ whether by contract or otherwise, or (b) ownership of more than
+ fifty percent (50%) of the outstanding shares or beneficial
+ ownership of such entity.
+
+2. License Grants and Conditions
+--------------------------------
+
+2.1. Grants
+
+Each Contributor hereby grants You a world-wide, royalty-free,
+non-exclusive license:
+
+(a) under intellectual property rights (other than patent or trademark)
+ Licensable by such Contributor to use, reproduce, make available,
+ modify, display, perform, distribute, and otherwise exploit its
+ Contributions, either on an unmodified basis, with Modifications, or
+ as part of a Larger Work; and
+
+(b) under Patent Claims of such Contributor to make, use, sell, offer
+ for sale, have made, import, and otherwise transfer either its
+ Contributions or its Contributor Version.
+
+2.2. Effective Date
+
+The licenses granted in Section 2.1 with respect to any Contribution
+become effective for each Contribution on the date the Contributor first
+distributes such Contribution.
+
+2.3. Limitations on Grant Scope
+
+The licenses granted in this Section 2 are the only rights granted under
+this License. No additional rights or licenses will be implied from the
+distribution or licensing of Covered Software under this License.
+Notwithstanding Section 2.1(b) above, no patent license is granted by a
+Contributor:
+
+(a) for any code that a Contributor has removed from Covered Software;
+ or
+
+(b) for infringements caused by: (i) Your and any other third party's
+ modifications of Covered Software, or (ii) the combination of its
+ Contributions with other software (except as part of its Contributor
+ Version); or
+
+(c) under Patent Claims infringed by Covered Software in the absence of
+ its Contributions.
+
+This License does not grant any rights in the trademarks, service marks,
+or logos of any Contributor (except as may be necessary to comply with
+the notice requirements in Section 3.4).
+
+2.4. Subsequent Licenses
+
+No Contributor makes additional grants as a result of Your choice to
+distribute the Covered Software under a subsequent version of this
+License (see Section 10.2) or under the terms of a Secondary License (if
+permitted under the terms of Section 3.3).
+
+2.5. Representation
+
+Each Contributor represents that the Contributor believes its
+Contributions are its original creation(s) or it has sufficient rights
+to grant the rights to its Contributions conveyed by this License.
+
+2.6. Fair Use
+
+This License is not intended to limit any rights You have under
+applicable copyright doctrines of fair use, fair dealing, or other
+equivalents.
+
+2.7. Conditions
+
+Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
+in Section 2.1.
+
+3. Responsibilities
+-------------------
+
+3.1. Distribution of Source Form
+
+All distribution of Covered Software in Source Code Form, including any
+Modifications that You create or to which You contribute, must be under
+the terms of this License. You must inform recipients that the Source
+Code Form of the Covered Software is governed by the terms of this
+License, and how they can obtain a copy of this License. You may not
+attempt to alter or restrict the recipients' rights in the Source Code
+Form.
+
+3.2. Distribution of Executable Form
+
+If You distribute Covered Software in Executable Form then:
+
+(a) such Covered Software must also be made available in Source Code
+ Form, as described in Section 3.1, and You must inform recipients of
+ the Executable Form how they can obtain a copy of such Source Code
+ Form by reasonable means in a timely manner, at a charge no more
+ than the cost of distribution to the recipient; and
+
+(b) You may distribute such Executable Form under the terms of this
+ License, or sublicense it under different terms, provided that the
+ license for the Executable Form does not attempt to limit or alter
+ the recipients' rights in the Source Code Form under this License.
+
+3.3. Distribution of a Larger Work
+
+You may create and distribute a Larger Work under terms of Your choice,
+provided that You also comply with the requirements of this License for
+the Covered Software. If the Larger Work is a combination of Covered
+Software with a work governed by one or more Secondary Licenses, and the
+Covered Software is not Incompatible With Secondary Licenses, this
+License permits You to additionally distribute such Covered Software
+under the terms of such Secondary License(s), so that the recipient of
+the Larger Work may, at their option, further distribute the Covered
+Software under the terms of either this License or such Secondary
+License(s).
+
+3.4. Notices
+
+You may not remove or alter the substance of any license notices
+(including copyright notices, patent notices, disclaimers of warranty,
+or limitations of liability) contained within the Source Code Form of
+the Covered Software, except that You may alter any license notices to
+the extent required to remedy known factual inaccuracies.
+
+3.5. Application of Additional Terms
+
+You may choose to offer, and to charge a fee for, warranty, support,
+indemnity or liability obligations to one or more recipients of Covered
+Software. However, You may do so only on Your own behalf, and not on
+behalf of any Contributor. You must make it absolutely clear that any
+such warranty, support, indemnity, or liability obligation is offered by
+You alone, and You hereby agree to indemnify every Contributor for any
+liability incurred by such Contributor as a result of warranty, support,
+indemnity or liability terms You offer. You may include additional
+disclaimers of warranty and limitations of liability specific to any
+jurisdiction.
+
+4. Inability to Comply Due to Statute or Regulation
+---------------------------------------------------
+
+If it is impossible for You to comply with any of the terms of this
+License with respect to some or all of the Covered Software due to
+statute, judicial order, or regulation then You must: (a) comply with
+the terms of this License to the maximum extent possible; and (b)
+describe the limitations and the code they affect. Such description must
+be placed in a text file included with all distributions of the Covered
+Software under this License. Except to the extent prohibited by statute
+or regulation, such description must be sufficiently detailed for a
+recipient of ordinary skill to be able to understand it.
+
+5. Termination
+--------------
+
+5.1. The rights granted under this License will terminate automatically
+if You fail to comply with any of its terms. However, if You become
+compliant, then the rights granted under this License from a particular
+Contributor are reinstated (a) provisionally, unless and until such
+Contributor explicitly and finally terminates Your grants, and (b) on an
+ongoing basis, if such Contributor fails to notify You of the
+non-compliance by some reasonable means prior to 60 days after You have
+come back into compliance. Moreover, Your grants from a particular
+Contributor are reinstated on an ongoing basis if such Contributor
+notifies You of the non-compliance by some reasonable means, this is the
+first time You have received notice of non-compliance with this License
+from such Contributor, and You become compliant prior to 30 days after
+Your receipt of the notice.
+
+5.2. If You initiate litigation against any entity by asserting a patent
+infringement claim (excluding declaratory judgment actions,
+counter-claims, and cross-claims) alleging that a Contributor Version
+directly or indirectly infringes any patent, then the rights granted to
+You by any and all Contributors for the Covered Software under Section
+2.1 of this License shall terminate.
+
+5.3. In the event of termination under Sections 5.1 or 5.2 above, all
+end user license agreements (excluding distributors and resellers) which
+have been validly granted by You or Your distributors under this License
+prior to termination shall survive termination.
+
+************************************************************************
+* *
+* 6. Disclaimer of Warranty *
+* ------------------------- *
+* *
+* Covered Software is provided under this License on an "as is" *
+* basis, without warranty of any kind, either expressed, implied, or *
+* statutory, including, without limitation, warranties that the *
+* Covered Software is free of defects, merchantable, fit for a *
+* particular purpose or non-infringing. The entire risk as to the *
+* quality and performance of the Covered Software is with You. *
+* Should any Covered Software prove defective in any respect, You *
+* (not any Contributor) assume the cost of any necessary servicing, *
+* repair, or correction. This disclaimer of warranty constitutes an *
+* essential part of this License. No use of any Covered Software is *
+* authorized under this License except under this disclaimer. *
+* *
+************************************************************************
+
+************************************************************************
+* *
+* 7. Limitation of Liability *
+* -------------------------- *
+* *
+* Under no circumstances and under no legal theory, whether tort *
+* (including negligence), contract, or otherwise, shall any *
+* Contributor, or anyone who distributes Covered Software as *
+* permitted above, be liable to You for any direct, indirect, *
+* special, incidental, or consequential damages of any character *
+* including, without limitation, damages for lost profits, loss of *
+* goodwill, work stoppage, computer failure or malfunction, or any *
+* and all other commercial damages or losses, even if such party *
+* shall have been informed of the possibility of such damages. This *
+* limitation of liability shall not apply to liability for death or *
+* personal injury resulting from such party's negligence to the *
+* extent applicable law prohibits such limitation. Some *
+* jurisdictions do not allow the exclusion or limitation of *
+* incidental or consequential damages, so this exclusion and *
+* limitation may not apply to You. *
+* *
+************************************************************************
+
+8. Litigation
+-------------
+
+Any litigation relating to this License may be brought only in the
+courts of a jurisdiction where the defendant maintains its principal
+place of business and such litigation shall be governed by laws of that
+jurisdiction, without reference to its conflict-of-law provisions.
+Nothing in this Section shall prevent a party's ability to bring
+cross-claims or counter-claims.
+
+9. Miscellaneous
+----------------
+
+This License represents the complete agreement concerning the subject
+matter hereof. If any provision of this License is held to be
+unenforceable, such provision shall be reformed only to the extent
+necessary to make it enforceable. Any law or regulation which provides
+that the language of a contract shall be construed against the drafter
+shall not be used to construe this License against a Contributor.
+
+10. Versions of the License
+---------------------------
+
+10.1. New Versions
+
+Mozilla Foundation is the license steward. Except as provided in Section
+10.3, no one other than the license steward has the right to modify or
+publish new versions of this License. Each version will be given a
+distinguishing version number.
+
+10.2. Effect of New Versions
+
+You may distribute the Covered Software under the terms of the version
+of the License under which You originally received the Covered Software,
+or under the terms of any subsequent version published by the license
+steward.
+
+10.3. Modified Versions
+
+If you create software not governed by this License, and you want to
+create a new license for such software, you may create and use a
+modified version of this License if you rename the license and remove
+any references to the name of the license steward (except to note that
+such modified license differs from this License).
+
+10.4. Distributing Source Code Form that is Incompatible With Secondary
+Licenses
+
+If You choose to distribute Source Code Form that is Incompatible With
+Secondary Licenses under the terms of this version of the License, the
+notice described in Exhibit B of this License must be attached.
+
+Exhibit A - Source Code Form License Notice
+-------------------------------------------
+
+ This Source Code Form is subject to the terms of the Mozilla Public
+ License, v. 2.0. If a copy of the MPL was not distributed with this
+ file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+If it is not possible or desirable to put the notice in a particular
+file, then You may include the notice in a location (such as a LICENSE
+file in a relevant directory) where a recipient would be likely to look
+for such a notice.
+
+You may add additional accurate notices of copyright ownership.
+
+Exhibit B - "Incompatible With Secondary Licenses" Notice
+---------------------------------------------------------
+
+ This Source Code Form is "Incompatible With Secondary Licenses", as
+ defined by the Mozilla Public License, v. 2.0.
diff --git a/README.md b/README.md
new file mode 100644
index 00000000..d6d1bae5
--- /dev/null
+++ b/README.md
@@ -0,0 +1,49 @@
+
+# Bulk Transaction Processor
+**Core Function**: Domain-specific bulk processing engine for financial operations.
+
+## Key Responsibilities
+- Validates and transforms raw financial data (loans, repayments, fees)
+- Applies business logic (interest calculations, payment allocations)
+- Generates audit trails and error reports
+- Prepares processed records for downstream systems
+
+## Inputs
+- CSV/Excel files via `/api/upload`
+- Direct API payloads to `/api/process`
+- Database polling from staging tables
+
+## Outputs
+- Standardized JSON to message queues (RabbitMQ/Kafka)
+- Callbacks to originating systems
+- Error reports in `ERROR_.csv`
+
+## Dependencies
+- Requires `ph-ee-connector-bulk` for outbound delivery
+- Integrates with accounting rule engines
+
+
+## SSL Configuration
+```yaml
+server:
+ ssl:
+ key-alias: "tomcat-https"
+ key-store: "classpath:keystore.jks"
+ key-store-type: JKS
+ key-password: ""
+ key-store-password: ""
+ port: 8443
+```
+#### NOTE: For disabling TLS, change the port to "8080" and add null values for all the "ssl" related fields.
+
+## Checkstyle
+Use below command to execute the checkstyle test.
+```shell
+./gradlew checkstyleMain
+```
+
+## Spotless
+Use below command to execute the spotless apply.
+```shell
+./gradlew spotlessApply
+```
diff --git a/build.gradle b/build.gradle
index 60be2b26..3d52e720 100644
--- a/build.gradle
+++ b/build.gradle
@@ -6,8 +6,12 @@ plugins {
id 'java'
id 'maven-publish'
id 'eclipse'
+ id 'checkstyle'
+ id 'org.springframework.boot' version '2.6.2'
+ id 'com.diffplug.spotless' version '6.19.0'
+ id "com.jfrog.artifactory" version '5.+'
}
-
+apply plugin: "com.jfrog.artifactory"
repositories {
mavenLocal()
maven {
@@ -15,28 +19,214 @@ repositories {
}
maven {
- url = uri('https://fynarfin.jfrog.io/artifactory/fyn-libs-snapshot-local/')
+ url = uri('https://mifos.jfrog.io/artifactory/phee-gradle-local')
+ }
+
+ maven {
+ url = uri('https://mifos.jfrog.io/artifactory/mifosx-gradle-local')
+ }
+}
+
+apply plugin:'com.diffplug.spotless'
+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/**'
+ indentWithSpaces(4)
+ endWithNewline()
+ trimTrailingWhitespace()
+ }
+
+ groovyGradle {
+ target '*.gradle', '**/*.gradle'
+ targetExclude '**/build/**'
+ greclipse()
+ indentWithSpaces(4)
+ endWithNewline()
+ trimTrailingWhitespace()
}
+ lineEndings 'UNIX'
+}
+
+ext {
+ camelVersion = '3.4.0'
+ springBootVersion = '2.6.2'
+ cucumberVersion = '7.8.1'
+ lambokVersion = '1.18.24'
}
dependencies {
- implementation 'org.mifos:ph-ee-connector-common:1.0.0-SNAPSHOT'
+ // spring dependency
+ implementation "org.springframework.boot:spring-boot-starter:$springBootVersion"
+ implementation "org.springframework.boot:spring-boot-starter-web:$springBootVersion"
+ implementation "org.springframework:spring-web:5.3.14"
+ implementation 'org.springframework.kafka:spring-kafka:2.8.1'
+ implementation "org.springframework.boot:spring-boot-starter-actuator:$springBootVersion"
+
+ // spring test dependency
+ testImplementation "org.springframework.boot:spring-boot-starter-test:$springBootVersion"
+
+ // camel dependency
+ implementation "org.apache.camel.springboot:camel-spring-boot-starter:$camelVersion"
+ implementation "org.apache.camel:camel-undertow:$camelVersion"
+ implementation "org.apache.camel:camel-http:$camelVersion"
+ implementation "org.apache.camel.springboot:camel-mail-starter:$camelVersion"
+ implementation "org.apache.camel:camel-jackson:$camelVersion"
+
+ // camel test dependency
+ testImplementation "org.apache.camel:camel-test:$camelVersion"
+ testImplementation "org.apache.camel:camel-test-spring-junit5:$camelVersion"
+
+ // cucumber test dependency
+ testImplementation "io.cucumber:cucumber-junit:$cucumberVersion"
+ testImplementation "io.cucumber:cucumber-spring:$cucumberVersion"
+ testImplementation "io.cucumber:cucumber-java:$cucumberVersion"
+
+ // miscellaneous dependency
+ implementation 'com.google.code.gson:gson:2.8.9'
+ implementation 'org.json:json:20210307'
+ implementation 'org.mifos:ph-ee-connector-common:1.8.1-gazelle'
implementation 'org.apache.camel.springboot:camel-spring-boot-starter:3.4.0'
implementation 'org.apache.camel:camel-undertow:3.4.0'
implementation 'org.springframework.boot:spring-boot-starter:2.5.2'
implementation 'org.springframework.boot:spring-boot-starter-web:2.5.2'
+ implementation 'org.apache.camel:camel-http:3.4.0'
+ implementation 'org.springframework:spring-web:5.3.19'
implementation 'com.amazonaws:aws-java-sdk:1.11.486'
+ implementation 'commons-io:commons-io:2.11.0'
+
+ implementation 'com.amazonaws:aws-java-sdk-s3:1.11.486'
+ //To be removed
+ implementation 'com.amazonaws:aws-java-sdk-dynamodb:1.11.486'
implementation 'com.azure:azure-storage-blob:12.12.0'
- implementation 'io.camunda:zeebe-client-java:1.1.0'
- implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-csv:2.12.0'
- implementation 'org.springframework.kafka:spring-kafka:2.5.8.RELEASE'
- testImplementation 'org.springframework.boot:spring-boot-starter-test:2.5.2'
+
+ implementation 'io.camunda:zeebe-client-java:8.1.23'
+ implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-csv:2.12.3'
+ implementation 'org.apache.tika:tika-core:1.4'
+ implementation 'org.apache.commons:commons-io:1.3.2'
+ implementation "org.projectlombok:lombok:$lambokVersion"
+ annotationProcessor "org.projectlombok:lombok:$lambokVersion"
+ checkstyle 'com.puppycrawl.tools:checkstyle:10.9.3'
+ checkstyle 'com.github.sevntu-checkstyle:sevntu-checks:1.44.1'
+ implementation 'com.diffplug.gradle.spotless:spotless:2.4.1'
+
+ // miscellaneous test dependency
+ testImplementation "com.google.truth:truth:1.1.3"
+ testImplementation 'com.google.code.gson:gson:2.9.0'
+ implementation 'io.rest-assured:rest-assured:4.4.0'
+
+ //retrofit
+ implementation 'com.squareup.retrofit2:retrofit:2.9.0'
+ implementation 'com.squareup.retrofit2:converter-jackson:2.9.0'
+ implementation('com.squareup.retrofit2:converter-gson:2.4.0')
+}
+
+configure(this) {
+ // NOTE: order matters!
+ apply plugin: 'java'
+ apply plugin: 'idea'
+ apply plugin: 'eclipse'
+ apply plugin: 'checkstyle'
+ apply plugin: 'com.diffplug.spotless'
+
+ configurations {
+ implementation.setCanBeResolved(true)
+ api.setCanBeResolved(true)
+ }
+ tasks.withType(JavaCompile) {
+ options.compilerArgs += [
+ "-Xlint:unchecked",
+ "-Xlint:cast",
+ "-Xlint:auxiliaryclass",
+ "-Xlint:deprecation",
+ "-Xlint:dep-ann",
+ "-Xlint:divzero",
+ "-Xlint:empty",
+ "-Xlint:exports",
+ "-Xlint:fallthrough",
+ "-Xlint:finally",
+ "-Xlint:module",
+ "-Xlint:opens",
+ "-Xlint:options",
+ "-Xlint:overloads",
+ "-Xlint:overrides",
+ "-Xlint:path",
+ "-Xlint:processing",
+ "-Xlint:removal",
+ "-Xlint:requires-automatic",
+ "-Xlint:requires-transitive-automatic",
+ "-Xlint:try",
+ "-Xlint:varargs",
+ "-Xlint:preview",
+ "-Xlint:static",
+ // -Werror needs to be disabled because EclipseLink's static weaving doesn't generate warning-free code
+ // and during an IntelliJ recompilation, it fails
+ //"-Werror",
+ "-Xmaxwarns",
+ 1500,
+ "-Xmaxerrs",
+ 1500
+ ]
+ options.deprecation = true
+ }
+ // Configuration for the spotless plugin
+ // https://github.com/diffplug/spotless/tree/main/plugin-gradle
+ spotless {
+ java {
+ targetExclude '**/build/**', '**/bin/**', '**/out/**'
+ importOrder() //sort imports alphabetically
+ removeUnusedImports()
+ eclipse().configFile "$rootDir/config/bulk-formatter.xml"
+ endWithNewline()
+ trimTrailingWhitespace()
+ // Enforce style modifier order
+ custom 'Modifier ordering', {
+ def modifierRanking = [
+ public : 1,
+ protected : 2,
+ private : 3,
+ abstract : 4,
+ default : 5,
+ static : 6,
+ final : 7,
+ transient : 8,
+ volatile : 9,
+ synchronized: 10,
+ native : 11,
+ strictfp : 12]
+ // Find any instance of multiple modifiers. Lead with a non-word character to avoid
+ // accidental matching against for instance, "an alternative default value"
+ it.replaceAll(/\W(?:public |protected |private |abstract |default |static |final |transient |volatile |synchronized |native |strictfp ){2,}/, {
+ // Do not replace the leading non-word character. Identify the modifiers
+ it.replaceAll(/(?:public |protected |private |abstract |default |static |final |transient |volatile |synchronized |native |strictfp ){2,}/, {
+ // Sort the modifiers according to the ranking above
+ it.split().sort({ modifierRanking[it] }).join(' ') + ' '
+ }
+ )
+ }
+ )
+ }
+ }
+ lineEndings 'UNIX'
+ }
+ // If we are running Gradle within Eclipse to enhance classes,
+ // set the classes directory to point to Eclipse's default build directory
+ if (project.hasProperty('env') && project.getProperty('env') == 'eclipse') {
+ sourceSets.main.java.outputDir = file("$projectDir/bin/main")
+ }
+ // Configuration for the Checkstyle plugin
+ // https://docs.gradle.org/current/userguide/checkstyle_plugin.html
+ dependencies {
+ checkstyle 'com.puppycrawl.tools:checkstyle:10.3.1'
+ checkstyle 'com.github.sevntu-checkstyle:sevntu-checks:1.42.0'
+ }
}
+
group = 'org.mifos'
-version = '0.0.1-SNAPSHOT'
+version = '2.0.0.mifos-SNAPSHOT'
description = 'ph-ee-processor-bulk'
-sourceCompatibility = '1.8'
+sourceCompatibility = '17'
publishing {
publications {
@@ -49,3 +239,31 @@ publishing {
tasks.withType(JavaCompile) {
options.encoding = 'UTF-8'
}
+
+
+
+// tasks.named('test') {
+// useJUnitPlatform()
+// }
+
+
+// configurations {
+// cucumberRuntime {
+// extendsFrom testImplementation
+// }
+// }
+
+// task cucumberCli() {
+// dependsOn assemble, testClasses
+// doLast {
+// javaexec {
+// main = "io.cucumber.core.cli.Main"
+// classpath = configurations.cucumberRuntime + sourceSets.main.output + sourceSets.test.output
+// args = [
+// '--plugin', 'pretty',
+// '--plugin', 'html:target/cucumber-report.html',
+// '--glue', 'org.mifos.processor.cucumber',
+// 'src/test/java/resources']
+// }
+// }
+// }
diff --git a/config/bulk-cleanup.xml b/config/bulk-cleanup.xml
new file mode 100644
index 00000000..67cb2b70
--- /dev/null
+++ b/config/bulk-cleanup.xml
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/config/bulk-formatter.xml b/config/bulk-formatter.xml
new file mode 100644
index 00000000..21a66024
--- /dev/null
+++ b/config/bulk-formatter.xml
@@ -0,0 +1,366 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml
new file mode 100644
index 00000000..5183efef
--- /dev/null
+++ b/config/checkstyle/checkstyle.xml
@@ -0,0 +1,266 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/config/checkstyle/suppressions.xml b/config/checkstyle/suppressions.xml
new file mode 100644
index 00000000..f4e5b54c
--- /dev/null
+++ b/config/checkstyle/suppressions.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index 490fda85..41d9927a 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 a4b44297..e750102e 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
index 2fe81a7d..1b6c7873 100755
--- a/gradlew
+++ b/gradlew
@@ -1,7 +1,7 @@
-#!/usr/bin/env sh
+#!/bin/sh
#
-# Copyright 2015 the original author or authors.
+# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -17,78 +17,113 @@
#
##############################################################################
-##
-## Gradle start up script for UN*X
-##
+#
+# Gradle start up script for POSIX generated by Gradle.
+#
+# Important for running:
+#
+# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+# noncompliant, but you have some other compliant shell such as ksh or
+# bash, then to run this script, type that shell name before the whole
+# command line, like:
+#
+# ksh Gradle
+#
+# Busybox and similar reduced shells will NOT work, because this script
+# requires all of these POSIX shell features:
+# * functions;
+# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+# * compound commands having a testable exit status, especially «case»;
+# * various built-in commands including «command», «set», and «ulimit».
+#
+# Important for patching:
+#
+# (2) This script targets any POSIX shell, so it avoids extensions provided
+# by Bash, Ksh, etc; in particular arrays are avoided.
+#
+# The "traditional" practice of packing multiple parameters into a
+# space-separated string is a well documented source of bugs and security
+# problems, so this is (mostly) avoided, by progressively accumulating
+# options in "$@", and eventually passing that to Java.
+#
+# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+# see the in-line comments for details.
+#
+# There are tweaks for specific operating systems such as AIX, CygWin,
+# 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
+# within the Gradle project.
+#
+# You can find Gradle at https://github.com/gradle/gradle/.
+#
##############################################################################
# Attempt to set APP_HOME
+
# Resolve links: $0 may be a link
-PRG="$0"
-# Need this for relative symlinks.
-while [ -h "$PRG" ] ; do
- ls=`ls -ld "$PRG"`
- link=`expr "$ls" : '.*-> \(.*\)$'`
- if expr "$link" : '/.*' > /dev/null; then
- PRG="$link"
- else
- PRG=`dirname "$PRG"`"/$link"
- fi
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+ APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+ [ -h "$app_path" ]
+do
+ ls=$( ls -ld "$app_path" )
+ link=${ls#*' -> '}
+ case $link in #(
+ /*) app_path=$link ;; #(
+ *) app_path=$APP_HOME$link ;;
+ esac
done
-SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >/dev/null
-APP_HOME="`pwd -P`"
-cd "$SAVED" >/dev/null
+
+APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle"
-APP_BASE_NAME=`basename "$0"`
+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"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
-MAX_FD="maximum"
+MAX_FD=maximum
warn () {
echo "$*"
-}
+} >&2
die () {
echo
echo "$*"
echo
exit 1
-}
+} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
-case "`uname`" in
- CYGWIN* )
- cygwin=true
- ;;
- Darwin* )
- darwin=true
- ;;
- MINGW* )
- msys=true
- ;;
- NONSTOP* )
- nonstop=true
- ;;
+case "$( uname )" in #(
+ CYGWIN* ) cygwin=true ;; #(
+ Darwin* ) darwin=true ;; #(
+ MSYS* | MINGW* ) msys=true ;; #(
+ NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
- JAVACMD="$JAVA_HOME/jre/sh/java"
+ JAVACMD=$JAVA_HOME/jre/sh/java
else
- JAVACMD="$JAVA_HOME/bin/java"
+ JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@@ -97,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
- JAVACMD="java"
+ 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.
Please set the JAVA_HOME variable in your environment to match the
@@ -105,79 +140,95 @@ location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
-if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
- MAX_FD_LIMIT=`ulimit -H -n`
- if [ $? -eq 0 ] ; then
- if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
- MAX_FD="$MAX_FD_LIMIT"
- fi
- ulimit -n $MAX_FD
- if [ $? -ne 0 ] ; then
- warn "Could not set maximum file descriptor limit: $MAX_FD"
- fi
- else
- warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
- fi
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+ case $MAX_FD in #(
+ max*)
+ MAX_FD=$( ulimit -H -n ) ||
+ warn "Could not query maximum file descriptor limit"
+ esac
+ case $MAX_FD in #(
+ '' | soft) :;; #(
+ *)
+ ulimit -n "$MAX_FD" ||
+ warn "Could not set maximum file descriptor limit to $MAX_FD"
+ esac
fi
-# For Darwin, add options to specify how the application appears in the dock
-if $darwin; then
- GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
-fi
+# Collect all arguments for the java command, stacking in reverse order:
+# * args from the command line
+# * the main class name
+# * -classpath
+# * -D...appname settings
+# * --module-path (only if needed)
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Cygwin or MSYS, switch paths to Windows format before running java
-if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
- APP_HOME=`cygpath --path --mixed "$APP_HOME"`
- CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
- JAVACMD=`cygpath --unix "$JAVACMD"`
-
- # We build the pattern for arguments to be converted via cygpath
- ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
- SEP=""
- for dir in $ROOTDIRSRAW ; do
- ROOTDIRS="$ROOTDIRS$SEP$dir"
- SEP="|"
- done
- OURCYGPATTERN="(^($ROOTDIRS))"
- # Add a user-defined pattern to the cygpath arguments
- if [ "$GRADLE_CYGPATTERN" != "" ] ; then
- OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
- fi
+if "$cygwin" || "$msys" ; then
+ APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+ CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+ JAVACMD=$( cygpath --unix "$JAVACMD" )
+
# Now convert the arguments - kludge to limit ourselves to /bin/sh
- i=0
- for arg in "$@" ; do
- CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
- CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
-
- if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
- eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
- else
- eval `echo args$i`="\"$arg\""
+ for arg do
+ if
+ case $arg in #(
+ -*) false ;; # don't mess with options #(
+ /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
+ [ -e "$t" ] ;; #(
+ *) false ;;
+ esac
+ then
+ arg=$( cygpath --path --ignore --mixed "$arg" )
fi
- i=`expr $i + 1`
+ # Roll the args list around exactly as many times as the number of
+ # args, so each arg winds up back in the position where it started, but
+ # possibly modified.
+ #
+ # NB: a `for` loop captures its iteration list before it begins, so
+ # changing the positional parameters here affects neither the number of
+ # iterations, nor the values presented in `arg`.
+ shift # remove old arg
+ set -- "$@" "$arg" # push replacement arg
done
- case $i in
- 0) set -- ;;
- 1) set -- "$args0" ;;
- 2) set -- "$args0" "$args1" ;;
- 3) set -- "$args0" "$args1" "$args2" ;;
- 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
- 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
- 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
- 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
- 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
- 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
- esac
fi
-# Escape application args
-save () {
- for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
- echo " "
-}
-APP_ARGS=`save "$@"`
+# 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.
+
+set -- \
+ "-Dorg.gradle.appname=$APP_BASE_NAME" \
+ -classpath "$CLASSPATH" \
+ org.gradle.wrapper.GradleWrapperMain \
+ "$@"
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+# set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
-# Collect all arguments for the java command, following the shell quoting and substitution rules
-eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+eval "set -- $(
+ printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+ xargs -n1 |
+ sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+ tr '\n' ' '
+ )" '"$@"'
exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
index 9109989e..ac1b06f9 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto init
+if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -54,7 +54,7 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-if exist "%JAVA_EXE%" goto init
+if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@@ -64,28 +64,14 @@ echo location of your Java installation.
goto fail
-:init
-@rem Get command-line arguments, handling Windows variants
-
-if not "%OS%" == "Windows_NT" goto win9xME_args
-
-:win9xME_args
-@rem Slurp the command line arguments.
-set CMD_LINE_ARGS=
-set _SKIP=2
-
-:win9xME_args_slurp
-if "x%~1" == "x" goto execute
-
-set CMD_LINE_ARGS=%*
-
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/kubernetes/phee-bulk-processor.yml b/kubernetes/phee-bulk-processor.yml
index 88816cdd..d9f4683a 100644
--- a/kubernetes/phee-bulk-processor.yml
+++ b/kubernetes/phee-bulk-processor.yml
@@ -44,4 +44,4 @@ spec:
selector:
app: ph-ee-bulk-processor
sessionAffinity: None
- type: LoadBalancer
\ No newline at end of file
+ type: LoadBalancer
diff --git a/src/.DS_Store b/src/.DS_Store
deleted file mode 100644
index eeb17bb1..00000000
Binary files a/src/.DS_Store and /dev/null differ
diff --git a/src/main/.DS_Store b/src/main/.DS_Store
deleted file mode 100644
index 6b3d8da9..00000000
Binary files a/src/main/.DS_Store and /dev/null differ
diff --git a/src/main/java/.DS_Store b/src/main/java/.DS_Store
deleted file mode 100644
index 298f56fa..00000000
Binary files a/src/main/java/.DS_Store and /dev/null differ
diff --git a/src/main/java/org/.DS_Store b/src/main/java/org/.DS_Store
deleted file mode 100644
index 57e5982b..00000000
Binary files a/src/main/java/org/.DS_Store and /dev/null differ
diff --git a/src/main/java/org/mifos/.DS_Store b/src/main/java/org/mifos/.DS_Store
deleted file mode 100644
index 83e9905c..00000000
Binary files a/src/main/java/org/mifos/.DS_Store and /dev/null differ
diff --git a/src/main/java/org/mifos/processor/BulkProcessorApplication.java b/src/main/java/org/mifos/processor/BulkProcessorApplication.java
index c523eee4..79f1e958 100644
--- a/src/main/java/org/mifos/processor/BulkProcessorApplication.java
+++ b/src/main/java/org/mifos/processor/BulkProcessorApplication.java
@@ -7,11 +7,16 @@
import com.fasterxml.jackson.dataformat.csv.CsvMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.apache.camel.Processor;
+import org.mifos.connector.common.interceptor.annotation.EnableJsonWebSignature;
+import org.mifos.processor.bulk.api.ApiOriginFilter;
+import org.mifos.processor.bulk.camel.config.HttpClientConfigurerTrustAllCACerts;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
+@EnableJsonWebSignature
public class BulkProcessorApplication {
public static void main(String[] args) {
@@ -23,8 +28,7 @@ public ObjectMapper objectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new JavaTimeModule());
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
- return objectMapper
- .setSerializationInclusion(JsonInclude.Include.NON_NULL)
+ return objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL)
.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true)
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
}
@@ -39,4 +43,19 @@ public CsvMapper csvMapper() {
return new CsvMapper();
}
+ @Bean
+ public HttpClientConfigurerTrustAllCACerts httpClientConfigurer() {
+ return new HttpClientConfigurerTrustAllCACerts();
+ }
+
+ @Bean
+ public FilterRegistrationBean apiOriginFilter() {
+ FilterRegistrationBean registration = new FilterRegistrationBean<>();
+ registration.setFilter(new ApiOriginFilter());
+ registration.addUrlPatterns("/**");
+ registration.setName("apiOriginFilter");
+ registration.setOrder(Integer.MIN_VALUE + 1);
+ return registration;
+ }
+
}
diff --git a/src/main/java/org/mifos/processor/bulk/ConfigurationValidator.java b/src/main/java/org/mifos/processor/bulk/ConfigurationValidator.java
new file mode 100644
index 00000000..516d3227
--- /dev/null
+++ b/src/main/java/org/mifos/processor/bulk/ConfigurationValidator.java
@@ -0,0 +1,107 @@
+package org.mifos.processor.bulk;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.List;
+import javax.annotation.PostConstruct;
+import org.mifos.processor.bulk.format.Standard;
+import org.mifos.processor.bulk.schema.Transaction;
+import org.mifos.processor.bulk.zeebe.worker.WorkerConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+@Component
+public class ConfigurationValidator {
+
+ public Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ @Value("${config.ordering.field}")
+ private String orderingField;
+
+ @Value("${config.completion-threshold-check.completion-threshold}")
+ private int completionRate;
+
+ @Value("${config.completion-threshold-check.max-retry}")
+ private int maxThresholdCheckRetry;
+
+ @Value("${config.formatting.standard}")
+ private String standard;
+
+ @Autowired
+ private WorkerConfig workerConfig;
+
+ @PostConstruct
+ private void validate() {
+ if (workerConfig.isOrderingWorkerEnabled) {
+ validateOrderingConfig();
+ }
+ if (workerConfig.isCompletionThresholdCheckEnabled) {
+ validateCompletionThresholdConfig();
+ validateMaxRetryFromThresholdCheck();
+ }
+ if (workerConfig.isFormattingWorkerEnabled) {
+ validateFormattingStandard();
+ }
+ }
+
+ private void validateMaxRetryFromThresholdCheck() {
+ if (maxThresholdCheckRetry <= 0) {
+ logger.error("Invalid maxThresholdCheckRetry count set. Needs to be +ve integer");
+ throw new ConfigurationValidationException("Invalid maxThresholdCheckRetry count set. Needs to be +ve integer");
+ }
+ }
+
+ // validates the standard to be used for formatting
+ private void validateFormattingStandard() {
+ String std = this.standard.toUpperCase();
+ try {
+ Standard standardEnum = Standard.valueOf(std);
+ logger.info("Configured formatting standard as >> {}", standardEnum.name());
+ return;
+ } catch (Exception e) {
+ logger.debug(e.getMessage());
+ }
+ List possibleStandards = new ArrayList<>();
+ for (Field f : Standard.class.getFields()) {
+ possibleStandards.add(f.getName());
+ }
+ throw new ConfigurationValidationException(
+ "Invalid standard configured for formatting data. Possible values are [" + String.join(",", possibleStandards) + "]");
+ }
+
+ // validates the ordering configuration
+ private void validateOrderingConfig() {
+ List possibleOrderingFields = new ArrayList<>();
+
+ for (Field field : Transaction.class.getDeclaredFields()) {
+ possibleOrderingFields.add(field.getName());
+ }
+
+ if (!possibleOrderingFields.contains(orderingField)) {
+ throw new ConfigurationValidationException(
+ "Invalid ordering field, possible values are [" + String.join(",", possibleOrderingFields) + "]");
+ }
+ }
+
+ // validates the success threshold related configuration
+ private void validateCompletionThresholdConfig() {
+ if (completionRate <= 0 || completionRate > 100) {
+ throw new ConfigurationValidationException("Invalid completion threshold value configured (value=" + completionRate + ").");
+ }
+
+ if (completionRate < 50) {
+ logger.warn("It is advised to set the completion threshold greater than 50. Currently configured as {}", completionRate);
+ }
+ }
+
+ // this exception is thrown when unexpected application config is set, and can't pass the ConfigurationValidator
+ public static class ConfigurationValidationException extends RuntimeException {
+
+ ConfigurationValidationException(String message) {
+ super(message);
+ }
+ }
+}
diff --git a/src/main/java/org/mifos/processor/bulk/HealthCheck.java b/src/main/java/org/mifos/processor/bulk/HealthCheck.java
index 9ecbe2a4..36285d18 100644
--- a/src/main/java/org/mifos/processor/bulk/HealthCheck.java
+++ b/src/main/java/org/mifos/processor/bulk/HealthCheck.java
@@ -1,14 +1,18 @@
package org.mifos.processor.bulk;
+import static org.mifos.processor.bulk.zeebe.ZeebeVariables.BATCH_ID;
+
import com.fasterxml.jackson.databind.MappingIterator;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.csv.CsvMapper;
import com.fasterxml.jackson.dataformat.csv.CsvSchema;
+import java.io.InputStream;
+import java.util.UUID;
import org.apache.camel.Exchange;
import org.apache.camel.LoggingLevel;
import org.apache.camel.builder.RouteBuilder;
import org.mifos.processor.bulk.file.FileTransferService;
-import org.mifos.processor.bulk.schema.Transaction;
+import org.mifos.processor.bulk.schema.TransactionOlder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -17,8 +21,6 @@
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Component;
-import java.util.UUID;
-
@Component
public class HealthCheck extends RouteBuilder {
@@ -51,34 +53,31 @@ public class HealthCheck extends RouteBuilder {
@Override
public void configure() {
- from("rest:GET:/")
- .setHeader(Exchange.HTTP_RESPONSE_CODE, constant(200))
- .setBody(constant(""));
-
- from("rest:GET:/channel/bulk/transfer/{fileName}")
- .id("transfer-details")
- .log(LoggingLevel.INFO, "## CHANNEL -> inbound bulk transfer request with ${header.fileName}")
- .process(exchange -> {
+ from("rest:GET:/").setHeader(Exchange.HTTP_RESPONSE_CODE, constant(200)).setBody(constant(""));
+
+ from("rest:GET:/channel/bulk/transfer/{fileName}").id("transfer-details")
+ .log(LoggingLevel.INFO, "## CHANNEL -> inbound bulk transfer request with ${header.fileName}").process(exchange -> {
String fileName = exchange.getIn().getHeader("fileName", String.class);
String batchId = UUID.randomUUID().toString();
+ exchange.setProperty(BATCH_ID, batchId);
// TODO: How to get sender information? Hard coded in Channel connector?
- byte[] csvFile = fileTransferService.downloadFile(fileName, bucketName);
+ InputStream csvFileInputStream = fileTransferService.streamFile(fileName, bucketName);
CsvSchema schema = CsvSchema.emptySchema().withHeader();
- MappingIterator readValues = csvMapper.readerWithSchemaFor(Transaction.class).with(schema).readValues(csvFile);
+ MappingIterator readValues = csvMapper.readerWithSchemaFor(TransactionOlder.class).with(schema)
+ .readValues(csvFileInputStream);
while (readValues.hasNext()) {
- Transaction current = readValues.next();
+ TransactionOlder current = readValues.next();
current.setBatchId(batchId);
- System.out.println(objectMapper.writeValueAsString(current));
- if (current.getPayment_mode().equals("gsma"))
+ logger.info("Writing string in kafka {}", objectMapper.writeValueAsString(current));
+ if (current.getPaymentMode().equals("gsma") || current.getPaymentMode().equals("afrimoney")) {
kafkaTemplate.send(gsmaTopicName, objectMapper.writeValueAsString(current));
- else if (current.getPayment_mode().equals("sclb"))
+ } else if (current.getPaymentMode().equals("sclb")) {
kafkaTemplate.send(slcbTopicName, objectMapper.writeValueAsString(current));
+ }
}
- })
- .setHeader(Exchange.HTTP_RESPONSE_CODE, constant(200))
- .setBody(constant(""));
+ }).setHeader(Exchange.HTTP_RESPONSE_CODE, constant(200)).setBody(exchange -> exchange.getProperty(BATCH_ID));
}
-}
\ No newline at end of file
+}
diff --git a/src/main/java/org/mifos/processor/bulk/OperationsAppConfig.java b/src/main/java/org/mifos/processor/bulk/OperationsAppConfig.java
new file mode 100644
index 00000000..4c754802
--- /dev/null
+++ b/src/main/java/org/mifos/processor/bulk/OperationsAppConfig.java
@@ -0,0 +1,46 @@
+package org.mifos.processor.bulk;
+
+import javax.annotation.PostConstruct;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+@Component
+public class OperationsAppConfig {
+
+ @Value("${operations-app.contactpoint}")
+ public String operationAppContactPoint;
+
+ @Value("${operations-app.endpoints.batch-transaction}")
+ public String batchTransactionEndpoint;
+
+ @Value("${operations-app.endpoints.batch-summary}")
+ public String batchSummaryEndpoint;
+
+ @Value("${operations-app.endpoints.batch-aggregate}")
+ public String batchAggregateEndpoint;
+
+ @Value("${operations-app.endpoints.auth}")
+ public String authEndpoint;
+
+ @Value("${operations-app.username}")
+ public String username;
+
+ @Value("${operations-app.password}")
+ public String password;
+
+ public String batchTransactionUrl;
+
+ public String batchSummaryUrl;
+
+ public String batchAggregateUrl;
+
+ public String authUrl;
+
+ @PostConstruct
+ private void setup() {
+ batchTransactionUrl = operationAppContactPoint + batchTransactionEndpoint;
+ batchSummaryUrl = operationAppContactPoint + batchSummaryEndpoint;
+ authUrl = operationAppContactPoint + authEndpoint;
+ batchAggregateUrl = operationAppContactPoint + batchAggregateEndpoint;
+ }
+}
diff --git a/src/main/java/org/mifos/processor/bulk/api/ApiOriginFilter.java b/src/main/java/org/mifos/processor/bulk/api/ApiOriginFilter.java
new file mode 100644
index 00000000..4137a6cf
--- /dev/null
+++ b/src/main/java/org/mifos/processor/bulk/api/ApiOriginFilter.java
@@ -0,0 +1,27 @@
+package org.mifos.processor.bulk.api;
+
+import static org.mifos.processor.bulk.camel.config.CamelProperties.HEADER_PLATFORM_TENANT_ID;
+
+import java.io.IOException;
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.filter.GenericFilterBean;
+
+public class ApiOriginFilter extends GenericFilterBean {
+
+ private Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ @Override
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
+ HttpServletRequest req = (HttpServletRequest) request;
+ String tenant = req.getHeader("" + HEADER_PLATFORM_TENANT_ID);
+ logger.debug("Tenant Name is : {}", tenant);
+ logger.info("Client IP Address: {}", req.getRemoteHost());
+ }
+
+}
diff --git a/src/main/java/org/mifos/processor/bulk/api/CallbackController.java b/src/main/java/org/mifos/processor/bulk/api/CallbackController.java
new file mode 100644
index 00000000..8dab4d5b
--- /dev/null
+++ b/src/main/java/org/mifos/processor/bulk/api/CallbackController.java
@@ -0,0 +1,67 @@
+package org.mifos.processor.bulk.api;
+
+import static org.mifos.processor.bulk.zeebe.ZeebeVariables.APPROVED_AMOUNT;
+import static org.mifos.processor.bulk.zeebe.ZeebeVariables.AUTHORIZATION_FAIL_REASON;
+import static org.mifos.processor.bulk.zeebe.ZeebeVariables.AUTHORIZATION_RESPONSE;
+import static org.mifos.processor.bulk.zeebe.ZeebeVariables.AUTHORIZATION_STATUS;
+import static org.mifos.processor.bulk.zeebe.ZeebeVariables.AUTHORIZATION_SUCCESSFUL;
+import static org.mifos.processor.bulk.zeebe.ZeebeVariables.CLIENT_CORRELATION_ID;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import io.camunda.zeebe.client.ZeebeClient;
+import java.time.Duration;
+import java.util.HashMap;
+import java.util.Map;
+import org.mifos.processor.bulk.schema.AuthorizationResponse;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+public class CallbackController {
+
+ @Autowired
+ private ZeebeClient zeebeClient;
+
+ @Autowired
+ ObjectMapper objectMapper;
+
+ protected Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ private static final String EXPECTED_AUTH_STATUS = "Y";
+
+ @PostMapping("/authorization/callback")
+ public ResponseEntity