├── .dockerignore
├── .env
├── .github
└── workflows
│ └── build-checks.yml
├── .gitignore
├── 3cn_realm.json
├── Dockerfile.3cn-parent-init
├── Dockerfile.update-3cn-parent
├── LICENSE
├── api-gateway
├── .dockerignore
├── .gitignore
├── Dockerfile.multistage
├── pom.xml
├── readme.md
└── src
│ └── main
│ ├── java
│ └── com
│ │ └── ubaid
│ │ └── ms
│ │ └── apigateway
│ │ ├── ApiGateway.java
│ │ ├── config
│ │ ├── Beans.java
│ │ ├── CorsConfig.java
│ │ ├── SecurityConfig.java
│ │ ├── SwaggerConfig.java
│ │ └── readme.md
│ │ ├── controller
│ │ ├── IndexController.java
│ │ └── InformationController.java
│ │ └── services
│ │ ├── InfoService.java
│ │ └── InfoServiceImpl.java
│ └── resources
│ ├── application-dev.properties
│ ├── application-local.properties
│ ├── application-prod.properties
│ ├── application.properties
│ └── config.properties
├── audit
├── .dockerignore
├── .gitignore
├── Dockerfile.multistage
├── pom.xml
├── readme.md
└── src
│ ├── main
│ ├── java
│ │ └── com
│ │ │ └── ubaid
│ │ │ └── ms
│ │ │ ├── AuditApplication.java
│ │ │ └── audit
│ │ │ ├── config
│ │ │ ├── Beans.java
│ │ │ ├── MessageBrokerConfig.java
│ │ │ ├── SecurityConfig.java
│ │ │ └── SwaggerConfig.java
│ │ │ ├── controller
│ │ │ ├── AuditController.java
│ │ │ └── InfoController.java
│ │ │ ├── dao
│ │ │ └── AuditDAO.java
│ │ │ ├── entity
│ │ │ └── Audit.java
│ │ │ ├── listener
│ │ │ └── ListenAuditLogs.java
│ │ │ └── service
│ │ │ ├── AuditService.java
│ │ │ ├── AuditServiceImpl.java
│ │ │ ├── InfoService.java
│ │ │ └── InfoServiceImpl.java
│ └── resources
│ │ ├── application-dev.properties
│ │ ├── application-local.properties
│ │ ├── application-prod.properties
│ │ ├── application.properties
│ │ ├── config.properties
│ │ └── db
│ │ └── migration
│ │ ├── V1__gh_301_create_audit_table.sql
│ │ └── V2__gh_360_replace_float_with_double.sql
│ └── test
│ └── java
│ └── com
│ └── ubaid
│ └── ms
│ └── auditservice
│ └── AuditApplicationTests.java
├── build-3cn-parent-image.sh
├── build-all-microservice-images.sh
├── clients
├── 3cn-react-client
│ ├── .dockerignore
│ ├── .env.dev
│ ├── .env.prod
│ ├── .eslintrc.json
│ ├── .gitignore
│ ├── Dockerfile
│ ├── README.md
│ ├── build-push-prod-ui-image.sh
│ ├── jsconfig.json
│ ├── nginx
│ │ └── nginx.conf
│ ├── package.json
│ ├── public
│ │ ├── favicon.ico
│ │ ├── index.html
│ │ ├── keycloak-dev.json
│ │ ├── keycloak-local.json
│ │ ├── keycloak-prod.json
│ │ ├── logo192.png
│ │ ├── logo512.png
│ │ ├── manifest.json
│ │ └── robots.txt
│ ├── src
│ │ ├── App.css
│ │ ├── App.js
│ │ ├── component
│ │ │ ├── auth
│ │ │ │ └── Authenticate.js
│ │ │ ├── convertionPaper
│ │ │ │ └── ConversionPaper.js
│ │ │ ├── down
│ │ │ │ └── ServiceDown.js
│ │ │ ├── footer
│ │ │ │ └── Footer.js
│ │ │ ├── header
│ │ │ │ └── Header.js
│ │ │ ├── selectCountry
│ │ │ │ └── CountrySelect.js
│ │ │ └── userinfo
│ │ │ │ └── UserInfo.js
│ │ ├── container
│ │ │ └── CurrencyConverter
│ │ │ │ └── CurrencyConverter.js
│ │ ├── hoc
│ │ │ └── Layout
│ │ │ │ └── Layout.js
│ │ ├── http
│ │ │ └── RequestHandler.js
│ │ ├── index.css
│ │ ├── index.js
│ │ ├── keycloak.js
│ │ ├── reportWebVitals.js
│ │ ├── setupTests.js
│ │ ├── store
│ │ │ ├── ActionTypes.js
│ │ │ ├── actions
│ │ │ │ ├── AuthAction.js
│ │ │ │ ├── ConvertCurrencyAction.js
│ │ │ │ ├── PopulateCountryAction.js
│ │ │ │ └── SelectCountryAction.js
│ │ │ └── reducers
│ │ │ │ ├── AuthReducer.js
│ │ │ │ ├── ConvertCurrencyReducer.js
│ │ │ │ ├── PopulateCountryReducer.js
│ │ │ │ └── SelectCountryReducer.js
│ │ └── util
│ │ │ └── ProtectedRoute.js
│ └── wireframes.drawio
└── CurrencyConversionReactNativeClient
│ ├── .buckconfig
│ ├── .eslintrc.js
│ ├── .flowconfig
│ ├── .gitattributes
│ ├── .gitignore
│ ├── .prettierrc.js
│ ├── .watchmanconfig
│ ├── App.js
│ ├── app.json
│ ├── babel.config.js
│ ├── index.js
│ ├── metro.config.js
│ └── package.json
├── common
├── .gitignore
├── dto
│ ├── .gitignore
│ ├── pom.xml
│ ├── readme.md
│ └── src
│ │ └── main
│ │ └── java
│ │ └── com
│ │ └── ubaid
│ │ └── ms
│ │ └── common
│ │ └── dto
│ │ ├── AuditDTO.java
│ │ ├── CountryCodeDTO.java
│ │ ├── CurrencyInfoDTO.java
│ │ ├── ExceptionDTO.java
│ │ ├── ExchangeRateDTO.java
│ │ ├── ExchangeValueDTO.java
│ │ ├── Rate.java
│ │ ├── ValueDTO.java
│ │ ├── auth
│ │ └── LoginCred.java
│ │ └── serviceinfo
│ │ ├── Commit.java
│ │ ├── Git.java
│ │ └── ServiceInformation.java
├── exception
│ ├── .gitignore
│ ├── pom.xml
│ ├── readme.md
│ └── src
│ │ └── main
│ │ └── java
│ │ └── com
│ │ └── ubaid
│ │ └── ms
│ │ └── common
│ │ └── util
│ │ └── exception
│ │ ├── CCException.java
│ │ └── ExchangeValueNotFound.java
├── pom.xml
├── readme.md
└── util
│ ├── .gitignore
│ ├── pom.xml
│ └── src
│ └── main
│ └── java
│ └── com
│ └── ubaid
│ └── ms
│ └── common
│ └── util
│ └── Constants.java
├── config
├── .dockerignore
├── .gitignore
├── Dockerfile.multistage
├── pom.xml
├── readme.md
└── src
│ └── main
│ ├── java
│ └── com
│ │ └── ubaid
│ │ └── ms
│ │ └── config
│ │ └── ConfigServer.java
│ └── resources
│ ├── application-dev.yml
│ ├── application-local.yml
│ ├── application-prod.yml
│ └── application.yml
├── country
├── .dockerignore
├── .gitignore
├── Dockerfile.multistage
├── pom.xml
├── readme.md
└── src
│ ├── main
│ ├── java
│ │ └── com
│ │ │ └── ubaid
│ │ │ └── ms
│ │ │ ├── CountryApplication.java
│ │ │ └── country
│ │ │ ├── advice
│ │ │ └── ExceptionController.java
│ │ │ ├── aop
│ │ │ ├── Logging.java
│ │ │ └── TargetMethods.java
│ │ │ ├── config
│ │ │ ├── Beans.java
│ │ │ ├── SecurityConfig.java
│ │ │ ├── SwaggerConfig.java
│ │ │ └── validator
│ │ │ │ └── AudienceValidator.java
│ │ │ ├── controller
│ │ │ ├── CountryController.java
│ │ │ └── InfoController.java
│ │ │ ├── dao
│ │ │ └── CountryCodeDAO.java
│ │ │ ├── entity
│ │ │ └── CountryCode.java
│ │ │ └── service
│ │ │ ├── CountryCodeService.java
│ │ │ ├── CountryCodeServiceImp.java
│ │ │ ├── InfoService.java
│ │ │ └── InfoServiceImpl.java
│ └── resources
│ │ ├── application-dev.properties
│ │ ├── application-local.properties
│ │ ├── application-prod.properties
│ │ ├── application.properties
│ │ ├── config.properties
│ │ └── db
│ │ └── changelog
│ │ ├── changes
│ │ ├── v0001.sql
│ │ ├── v0002.sql
│ │ ├── v0003.sql
│ │ ├── v0004-add_column_in_country_code_table.sql
│ │ ├── v0005-updating_iso_column_to_integer.sql
│ │ ├── v0005a-correcting_iso_column_to10_varchar.sql
│ │ └── v0006-populate_iso_code_column_in_country_code_table.sql
│ │ └── db.changelog-master.yaml
│ └── test
│ ├── java
│ └── com
│ │ └── ubaid
│ │ └── ms
│ │ └── counteryservice
│ │ └── CountryApplicationTests.java
│ └── resources
│ └── application.properties
├── currency-conversion
├── .dockerignore
├── .gitignore
├── Dockerfile.multistage
├── pom.xml
├── readme.md
├── runAllTests.sh
└── src
│ ├── main
│ ├── java
│ │ └── com
│ │ │ └── ubaid
│ │ │ └── ms
│ │ │ ├── CurrencyConversionApp.java
│ │ │ └── currencyconversion
│ │ │ ├── aop
│ │ │ ├── Logging.java
│ │ │ └── TargetMethods.java
│ │ │ ├── config
│ │ │ ├── Beans.java
│ │ │ ├── Config.java
│ │ │ ├── MessageBrokerConfig.java
│ │ │ ├── SecurityConfig.java
│ │ │ └── SwaggerConfig.java
│ │ │ ├── controller
│ │ │ ├── CurrencyConversionController.java
│ │ │ └── InfoController.java
│ │ │ ├── entity
│ │ │ └── Limit.java
│ │ │ ├── exceptionController
│ │ │ └── ExceptionController.java
│ │ │ ├── feignProxy
│ │ │ ├── CurrencyConversionServiceProxy.java
│ │ │ └── CurrencyExchangeServiceProxy.java
│ │ │ ├── service
│ │ │ ├── AuditService.java
│ │ │ ├── AuditServiceImpl.java
│ │ │ ├── AuthService.java
│ │ │ ├── AuthServiceImpl.java
│ │ │ ├── CurrencyConversionService.java
│ │ │ ├── CurrencyConversionServiceImp.java
│ │ │ ├── InfoService.java
│ │ │ ├── InfoServiceImpl.java
│ │ │ ├── RequestService.java
│ │ │ └── RequestServiceImpl.java
│ │ │ └── util
│ │ │ └── BearerToken.java
│ └── resources
│ │ ├── application-dev.properties
│ │ ├── application-local.properties
│ │ ├── application-prod.properties
│ │ ├── application.properties
│ │ └── config.properties
│ └── test
│ └── resources
│ ├── application.properties
│ └── config.properties
├── currency-exchange
├── .dockerignore
├── .gitignore
├── Dockerfile.multistage
├── pom.xml
├── readme.md
└── src
│ ├── main
│ ├── java
│ │ └── com
│ │ │ └── ubaid
│ │ │ └── ms
│ │ │ ├── CurrencyExchangeServiceApplication.java
│ │ │ └── currencyexchangeservice
│ │ │ ├── aop
│ │ │ ├── Logging.java
│ │ │ └── TargetMethods.java
│ │ │ ├── config
│ │ │ ├── Beans.java
│ │ │ ├── Config.java
│ │ │ ├── SecurityConfig.java
│ │ │ ├── SwaggerConfig.java
│ │ │ └── validator
│ │ │ │ └── AudienceValidator.java
│ │ │ ├── controller
│ │ │ ├── CurrencyExchangeController.java
│ │ │ ├── ExceptionController.java
│ │ │ └── InfoController.java
│ │ │ ├── dao
│ │ │ └── ExchangeRateDAO.java
│ │ │ ├── entity
│ │ │ └── ExchangeRate.java
│ │ │ ├── service
│ │ │ ├── ExchangeRateService.java
│ │ │ ├── ExchangeRateServiceImp.java
│ │ │ ├── InfoService.java
│ │ │ ├── InfoServiceImpl.java
│ │ │ ├── ServerInfoService.java
│ │ │ └── ServerInfoServiceImpl.java
│ │ │ ├── task
│ │ │ └── PopulateDBWithExchangeRates.java
│ │ │ └── utility
│ │ │ └── ExchangeRateDTOConverter.java
│ └── resources
│ │ ├── application-dev.properties
│ │ ├── application-local.properties
│ │ ├── application-prod.properties
│ │ ├── application.properties
│ │ ├── config.properties
│ │ ├── db
│ │ └── changelog
│ │ │ ├── changes
│ │ │ └── v00001.sql
│ │ │ └── db.changelog-master.yaml
│ │ └── exchangeRates.json
│ └── test
│ ├── java
│ └── com
│ │ └── ubaid
│ │ └── ms
│ │ ├── currency_conversion_service
│ │ └── ContextTest.java
│ │ └── currencyexchangeservice
│ │ ├── service
│ │ └── ExchangeRateServiceImpTest.java
│ │ ├── task
│ │ └── PopulateDBWithExchangeRatesTest.java
│ │ └── utility
│ │ └── ExchangeRateDTOConverterTest.java
│ └── resources
│ ├── application.properties
│ └── exchangeRates.json
├── discovery
├── .dockerignore
├── .gitignore
├── Dockerfile.multistage
├── pom.xml
├── readme.md
└── src
│ └── main
│ ├── java
│ └── com
│ │ └── ubaid
│ │ └── ms
│ │ └── discovery
│ │ └── DiscoveryApp.java
│ └── resources
│ └── application.properties
├── docker-compose-multi-stage-build.yml
├── envcn
├── .env
├── auth-db
│ ├── Dockerfile
│ ├── buid-push-prod-image.sh
│ └── sql
│ │ └── dump.sql
├── db
│ ├── Dockerfile
│ └── init.sql
├── docker-compose-multi-stage-build.yml
├── elasticsearch
│ ├── Dockerfile
│ └── config
│ │ └── elasticsearch.yml
├── kc
│ └── Dockerfile
├── kibana
│ ├── Dockerfile
│ └── config
│ │ └── kibana.yml
├── logstash
│ ├── Dockerfile
│ ├── config
│ │ └── logstash.yml
│ └── pipeline
│ │ └── logstash.conf
├── rabbitmq
│ └── Dockerfile
├── run-multi-stage.sh
└── zipkin
│ └── Dockerfile
├── install-maven-jdk17.sh
├── k8s
├── configs.yml
├── deployments.yml
├── docx
│ ├── moreinfo.md
│ └── readme.md
├── housekeeping
│ ├── delete-all-configMaps.sh
│ ├── delete-all-deployments.sh
│ ├── delete-all-ingress.sh
│ ├── delete-all-pv-and-pvc.sh
│ └── delete-all-services.sh
├── ingress.yml
├── k8s-down.sh
├── k8s-up.sh
├── minikube
│ └── install_minikube_kubectl.sh
├── pvcs.yml
├── pvs.yml
└── services.yml
├── math
├── .dockerignore
├── .gitignore
├── Dockerfile.multistage
├── pom.xml
├── readme.md
└── src
│ └── main
│ ├── java
│ └── com
│ │ └── ubaid
│ │ └── ms
│ │ └── math
│ │ ├── MathApplication.java
│ │ ├── aop
│ │ ├── Logging.java
│ │ └── TargetMethods.java
│ │ ├── config
│ │ ├── Beans.java
│ │ ├── SecurityConfig.java
│ │ ├── SwaggerConfig.java
│ │ └── validator
│ │ │ └── AudienceValidator.java
│ │ ├── controller
│ │ ├── ExceptionController.java
│ │ ├── InfoController.java
│ │ └── MathController.java
│ │ └── service
│ │ ├── InfoService.java
│ │ ├── InfoServiceImpl.java
│ │ ├── MathService.java
│ │ ├── MathServiceImp.java
│ │ ├── ServerInfoService.java
│ │ └── ServerInfoServiceImpl.java
│ └── resources
│ ├── application-dev.properties
│ ├── application-local.properties
│ ├── application-prod.properties
│ ├── application.properties
│ └── config.properties
├── misc
└── docker-compose-postgres.yml
├── moreinfo.md
├── pom.xml
├── pull-all-microservice-images.sh
├── push-all-microservice-images.sh
├── readme.md
├── resource
├── 3cn-parent-image
│ └── readme.md
├── Auth Flow 1.drawio
├── api-composer-swagger-ui-2.png
├── api-composer-swagger-ui.png
├── auth
│ ├── 3cn-react-client-access-type.png
│ ├── 3cn-react-client.png
│ ├── auth-flow-v1.png
│ ├── auth-flow.md
│ ├── img.png
│ └── img_1.png
├── checkstyle
│ ├── google_checks.xml
│ └── readme.md
├── copy-access-token.png
├── country-service-swagger-ui-2.png
├── country-service-swagger-ui.png
├── create-index-for-logging.md
├── create-index.PNG
├── definition-drop-down.png
├── effective-java
│ └── readme.md
├── execute-exchnage-request.png
├── execute-login-reqeust.png
├── how-to-use-swagger.md
├── how-to-user-swagger.png
├── install-require-softwares.md
├── java-home.png
├── kibana-dashboard.png
├── lucid-diagrams
│ └── 3cnArchitecture.png
├── mvn-version.png
├── pase-acces-token.png
├── see-the-response.png
└── swagger-authorize-request.png
├── run-multi-stage.sh
├── update-3cn-parent-image.sh
└── user
├── .dockerignore
├── .gitignore
├── Dockerfile.multistage
├── pom.xml
├── readme.md
└── src
├── main
├── java
│ └── com
│ │ └── ubaid
│ │ └── ms
│ │ ├── UserApp.java
│ │ └── user
│ │ ├── advice
│ │ └── ExceptionHandlerController.java
│ │ ├── aop
│ │ ├── Logging.java
│ │ └── TargetMethods.java
│ │ ├── config
│ │ ├── Beans.java
│ │ ├── SecurityConfig.java
│ │ └── SwaggerConfig.java
│ │ ├── controller
│ │ ├── InfoController.java
│ │ └── UserServiceController.java
│ │ ├── feignproxy
│ │ └── AuthTokenServiceProxy.java
│ │ └── service
│ │ ├── AccessTokenService.java
│ │ ├── AccessTokenServiceImpl.java
│ │ ├── InfoService.java
│ │ └── InfoServiceImpl.java
└── resources
│ ├── application-dev.properties
│ ├── application-local.properties
│ ├── application-prod.properties
│ ├── application.properties
│ └── config.properties
└── test
└── java
└── com
└── ubaid
└── ms
└── userservice
└── UserAppTests.java
/.env:
--------------------------------------------------------------------------------
1 | APP_VERSION=0.0.3-SNAPSHOT
--------------------------------------------------------------------------------
/.github/workflows/build-checks.yml:
--------------------------------------------------------------------------------
1 | # This workflow will build a Java project with Maven
2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
3 |
4 | name: Java CI with Maven develop & master Branch
5 |
6 | on:
7 | pull_request:
8 | branches:
9 | - develop
10 | - master
11 |
12 | jobs:
13 | build:
14 |
15 | runs-on: ubuntu-latest
16 |
17 | steps:
18 | - uses: actions/checkout@v2
19 | - name: Set up JDK 17
20 | uses: actions/setup-java@v1
21 | with:
22 | java-version: 17
23 | - name: Build 3CN Modules
24 | run: mvn clean install -DskipTests --file common/pom.xml
25 | - name: Build 3CN Parent
26 | run: mvn clean install -N -DskipTests --file pom.xml
27 | - name: Build 3CN Whole Project
28 | run: mvn -B package -DskipTests --file pom.xml
29 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /.metadata/
2 | .idea
3 | .vscode
4 | /currency-conversion-client
5 | /currency-conversion-api
6 | /CC-DTO
7 | /CC-Exception
8 | *.iml
9 | /localtunnel
--------------------------------------------------------------------------------
/Dockerfile.3cn-parent-init:
--------------------------------------------------------------------------------
1 | FROM maven:3.8-openjdk-17-slim
2 | WORKDIR /3cn
3 | COPY . .
4 | RUN mvn install -DskipTests --file common/pom.xml \
5 | && mvn install -N -DskipTests --file pom.xml \
6 | && mvn install -DskipTests --file pom.xml \
7 | && mv /3cn/.git / \
8 | && rm -rf /3cn \
9 | && rm -rf /root/.m2/repository/com/ubaid/ms/currency-conversion \
10 | && rm -rf /root/.m2/repository/com/ubaid/ms/audit \
11 | && rm -rf /root/.m2/repository/com/ubaid/ms/country \
12 | && rm -rf /root/.m2/repository/com/ubaid/ms/math \
13 | && rm -rf /root/.m2/repository/com/ubaid/ms/currency-exchange \
14 | && rm -rf /root/.m2/repository/com/ubaid/ms/discovery \
15 | && rm -rf /root/.m2/repository/com/ubaid/ms/api-gateway \
16 | && rm -rf /root/.m2/repository/com/ubaid/ms/config \
17 | && rm -rf /root/.m2/repository/com/ubaid/ms/user
--------------------------------------------------------------------------------
/Dockerfile.update-3cn-parent:
--------------------------------------------------------------------------------
1 | FROM 3cn-parent:0.0.3-SNAPSHOT
2 | WORKDIR /3cn
3 | COPY . .
4 | RUN mvn install -DskipTests --file common/pom.xml \
5 | && mvn install -N -DskipTests --file pom.xml \
6 | && mvn install -DskipTests --file pom.xml \
7 | && mv /3cn/.git / \
8 | && rm -rf /3cn \
9 | && rm -rf /root/.m2/repository/com/ubaid/ms/currency-conversion \
10 | && rm -rf /root/.m2/repository/com/ubaid/ms/audit \
11 | && rm -rf /root/.m2/repository/com/ubaid/ms/country \
12 | && rm -rf /root/.m2/repository/com/ubaid/ms/math \
13 | && rm -rf /root/.m2/repository/com/ubaid/ms/currency-exchange \
14 | && rm -rf /root/.m2/repository/com/ubaid/ms/discovery \
15 | && rm -rf /root/.m2/repository/com/ubaid/ms/api-gateway \
16 | && rm -rf /root/.m2/repository/com/ubaid/ms/config \
17 | && rm -rf /root/.m2/repository/com/ubaid/ms/user
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Ubaid ur Rehman
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/api-gateway/.dockerignore:
--------------------------------------------------------------------------------
1 | /target
2 | .gitignore
3 | *.iml
4 | Dockerfile
5 | Dockerfile.debug
6 | Dockerfile.multistage
7 | readme.md
--------------------------------------------------------------------------------
/api-gateway/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 | !**/src/main/**
5 | !**/src/test/**
6 |
7 | ### STS ###
8 | .apt_generated
9 | .classpath
10 | .factorypath
11 | .project
12 | .settings
13 | .springBeans
14 | .sts4-cache
15 |
16 | ### IntelliJ IDEA ###
17 | .idea
18 | *.iws
19 | *.iml
20 | *.ipr
21 |
22 | ### NetBeans ###
23 | /nbproject/private/
24 | /nbbuild/
25 | /dist/
26 | /nbdist/
27 | /.nb-gradle/
28 | build/
29 |
30 | ### VS Code ###
31 | .vscode/
32 |
--------------------------------------------------------------------------------
/api-gateway/Dockerfile.multistage:
--------------------------------------------------------------------------------
1 | ARG APP_VERSION
2 | FROM ubaidurehman/3cn-parent:${APP_VERSION} as build
3 | LABEL maintainer="urehman.bese16seecs@seecs.edu.pk"
4 | VOLUME /tmp
5 | WORKDIR /
6 | ADD . .
7 | RUN mvn clean install -DskipTests
8 |
9 | FROM openjdk:17-slim
10 | VOLUME /tmp
11 | WORKDIR /
12 | EXPOSE 8755
13 | ARG APP_VERSION
14 | COPY --from=build /target/api-gateway-${APP_VERSION}.jar service.jar
15 | ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-Dspring.profiles.active=dev","-jar","/service.jar"]
16 |
--------------------------------------------------------------------------------
/api-gateway/readme.md:
--------------------------------------------------------------------------------
1 | ### About
2 | - A server which is responsible to reroute request to the resource server
3 |
4 | Dependencies
5 | ------------
6 | - #### Cloud
7 | - ##### Config Client
8 | - spring-cloud-starter-config
9 | - ##### Naming Server Client
10 | - spring-cloud-starter-netflix-eureka-client
11 | - ##### API Gateway
12 | - spring-cloud-starter-gateway
13 | - ##### Distributed Tracing
14 | - spring-cloud-sleuth-zipkin
15 | - spring-cloud-starter-sleuth
16 | - #### Security
17 | - ##### Spring Security
18 | - spring-cloud-starter-security
19 | - ##### [OAuth2 Resource Server](./../moreinfo.md#Resource-server)
20 | - spring-boot-starter-oauth2-resource-server
21 | - ##### [OAuth2 Client](./../moreinfo.md#OAuth2-client)
22 | - spring-boot-starter-oauth2-client
23 | - #### Logstash (Sending logs to Logstash)
24 | - reactive-logstash-logging-spring-boot-starter
25 | - #### [Dependencies From Parent](./../moreinfo.md#Dependencies-from-parent)
26 |
27 | [Distributed Tracing](./../moreinfo.md#distributed-tracing)
28 | -----------------------------------------------------------
29 | [ELK Stack](./../moreinfo.md#elk-stack)
30 | ---------------------------------------
--------------------------------------------------------------------------------
/api-gateway/src/main/java/com/ubaid/ms/apigateway/ApiGateway.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.apigateway;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
6 |
7 | /**
8 | * Re-routes the incoming request to down-stream services according to the URL match pattern.
9 | *
10 | * @author ubaid
11 | */
12 | @EnableDiscoveryClient
13 | @SpringBootApplication
14 | public class ApiGateway {
15 | public static void main(String[] args) {
16 | SpringApplication.run(ApiGateway.class, args);
17 | }
18 | }
--------------------------------------------------------------------------------
/api-gateway/src/main/java/com/ubaid/ms/apigateway/config/Beans.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.apigateway.config;
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper;
4 | import org.springframework.beans.factory.config.ConfigurableBeanFactory;
5 | import org.springframework.context.annotation.Bean;
6 | import org.springframework.context.annotation.Scope;
7 |
8 | public class Beans {
9 |
10 | @Bean
11 | @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
12 | public ObjectMapper objectMapper() {
13 | return new ObjectMapper();
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/api-gateway/src/main/java/com/ubaid/ms/apigateway/config/SwaggerConfig.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.apigateway.config;
2 |
3 | import static com.ubaid.ms.common.util.Constants.*;
4 | import lombok.RequiredArgsConstructor;
5 | import lombok.extern.slf4j.Slf4j;
6 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
7 | import org.springframework.cloud.client.discovery.DiscoveryClient;
8 | import org.springframework.context.annotation.Primary;
9 | import org.springframework.stereotype.Component;
10 | import springfox.documentation.swagger.web.SwaggerResource;
11 | import springfox.documentation.swagger.web.SwaggerResourcesProvider;
12 | import java.util.List;
13 |
14 | @Component
15 | @Primary
16 | @EnableAutoConfiguration
17 | @RequiredArgsConstructor
18 | @Slf4j
19 | public class SwaggerConfig implements SwaggerResourcesProvider {
20 |
21 | private final DiscoveryClient discoveryClient;
22 |
23 | @Override
24 | public List get() {
25 | List allServices = discoveryClient.getServices();
26 | log.debug("All Services: {}", allServices);
27 | return allServices
28 | .stream()
29 | .filter(serviceName -> !serviceName.equalsIgnoreCase(API_GATEWAY))
30 | .map(this::swaggerResource)
31 | .toList();
32 | }
33 |
34 | private SwaggerResource swaggerResource(String name) {
35 | SwaggerResource swaggerResource = new SwaggerResource();
36 | swaggerResource.setName(name);
37 | swaggerResource.setLocation("/" + name + API_DOCS_PATH);
38 | swaggerResource.setSwaggerVersion(APP_VERSION);
39 | return swaggerResource;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/api-gateway/src/main/java/com/ubaid/ms/apigateway/config/readme.md:
--------------------------------------------------------------------------------
1 | - Security Configuration of Spring Cloud Gateway
2 | ```java
3 | @Configuration
4 | @EnableWebFluxSecurity
5 | @EnableGlobalMethodSecurity(jsr250Enabled = true)
6 | public class SecurityConfig {
7 |
8 | @Bean
9 | public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
10 | http
11 | .authorizeExchange()
12 | .anyExchange()
13 | .authenticated()
14 | .and().oauth2ResourceServer().jwt();
15 |
16 | http.csrf().disable();
17 |
18 | return http.build();
19 | }
20 | }
21 | ```
22 |
23 | - Explanation
24 | 1. `@Configuration` Indicates that a class declares one or more `@Bean` methods and may be processed by the Spring container to generate bean definitions and service requests for those beans at runtime.
25 | 2. `@EnableWebFluxSecurity` As Spring Cloud API Gateway is based upon Reactor Project, so enabling `WebFluxSecurity`
26 | 3. `@EnableGlobalMethodSecurity(jsr250Enabled = true)` property allows us to use the `@RoleAllowed` annotation on methods
27 | 4. `SecurityWebFilterChain` bean which configuring security to authenticate all requests and adding support of `OAuth2` Server, (It is behaving both Client and Resource Server)
28 | 5. `spring.security.oauth2.resourceserver.jwt.issuer-uri` `ReactiveJwtDecoder` OIDC issuer Location
29 | 6. Along with this, we have to add a provider (Auth Server) and Clients (Resource Servers) (check the props files)
30 |
--------------------------------------------------------------------------------
/api-gateway/src/main/java/com/ubaid/ms/apigateway/controller/IndexController.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.apigateway.controller;
2 |
3 | import org.springframework.http.HttpStatus;
4 | import org.springframework.http.server.reactive.ServerHttpResponse;
5 | import org.springframework.web.bind.annotation.GetMapping;
6 | import org.springframework.web.bind.annotation.RestController;
7 | import reactor.core.publisher.Mono;
8 |
9 | import java.net.URI;
10 |
11 | @RestController(value = "/")
12 | public class IndexController {
13 |
14 | @GetMapping(value = "/")
15 | public Mono index(ServerHttpResponse response) {
16 | response.setStatusCode(HttpStatus.PERMANENT_REDIRECT);
17 | response.getHeaders().setLocation(URI.create("/swagger-ui/index.html"));
18 | return response.setComplete();
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/api-gateway/src/main/java/com/ubaid/ms/apigateway/controller/InformationController.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.apigateway.controller;
2 |
3 | import com.ubaid.ms.apigateway.services.InfoService;
4 | import com.ubaid.ms.common.dto.serviceinfo.ServiceInformation;
5 | import java.util.List;
6 | import java.util.Map;
7 | import java.util.stream.Collectors;
8 | import lombok.RequiredArgsConstructor;
9 | import org.springframework.cloud.client.discovery.DiscoveryClient;
10 | import org.springframework.http.ResponseEntity;
11 | import org.springframework.web.bind.annotation.GetMapping;
12 | import org.springframework.web.bind.annotation.RequestMapping;
13 | import org.springframework.web.bind.annotation.RestController;
14 | import reactor.core.publisher.Mono;
15 |
16 | @RestController
17 | @RequestMapping(value = "api/api-gateway/v1/info")
18 | @RequiredArgsConstructor
19 | public class InformationController {
20 |
21 | private final DiscoveryClient discoveryClient;
22 | private final InfoService infoService;
23 |
24 | @GetMapping("services")
25 | public Mono>> getAllServices() {
26 | List allServices = discoveryClient.getServices();
27 | Map servicesWithInfoURI = allServices
28 | .stream()
29 | .collect(Collectors.toMap(key -> key, value -> "api/" + value + "/v1/info"));
30 | return Mono.just(ResponseEntity.ok(servicesWithInfoURI));
31 | }
32 |
33 | @GetMapping
34 | Mono> get() {
35 | return Mono.just(ResponseEntity.ok(infoService.get()));
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/api-gateway/src/main/java/com/ubaid/ms/apigateway/services/InfoService.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.apigateway.services;
2 |
3 | import com.ubaid.ms.common.dto.serviceinfo.ServiceInformation;
4 |
5 | public interface InfoService {
6 | ServiceInformation get();
7 | }
8 |
--------------------------------------------------------------------------------
/api-gateway/src/main/java/com/ubaid/ms/apigateway/services/InfoServiceImpl.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.apigateway.services;
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper;
4 | import com.netflix.appinfo.ApplicationInfoManager;
5 | import com.ubaid.ms.common.dto.serviceinfo.ServiceInformation;
6 | import com.ubaid.ms.common.dto.serviceinfo.ServiceInformationBuilder;
7 | import lombok.RequiredArgsConstructor;
8 | import lombok.extern.slf4j.Slf4j;
9 | import org.springframework.boot.actuate.info.InfoEndpoint;
10 | import org.springframework.stereotype.Service;
11 |
12 | @Service
13 | @Slf4j
14 | @RequiredArgsConstructor
15 | public class InfoServiceImpl implements InfoService {
16 |
17 | private final InfoEndpoint infoEndpoint;
18 | private final ObjectMapper objectMapper;
19 | private final ApplicationInfoManager applicationInfoManager;
20 |
21 | @Override
22 | public ServiceInformation get() {
23 | ServiceInformationBuilder builder = ServiceInformationBuilder
24 | .builder(objectMapper.convertValue(infoEndpoint.info(), ServiceInformation.class));
25 | builder.name(applicationInfoManager.getInfo().getAppName());
26 | ServiceInformation serviceInformation = builder.build();
27 | log.debug("Service Information: {}", serviceInformation);
28 | return serviceInformation;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/api-gateway/src/main/resources/application-dev.properties:
--------------------------------------------------------------------------------
1 | #------------------------Config Client--------------------------#
2 | spring.config.import=optional:configserver:http://config:8888
3 | spring.cloud.config.profile=dev
4 | spring.cloud.config.fail-fast=true
5 | spring.cloud.config.request-connect-timeout=30000
6 | spring.cloud.config.request-read-timeout=360000
--------------------------------------------------------------------------------
/api-gateway/src/main/resources/application-local.properties:
--------------------------------------------------------------------------------
1 | #------------------------Config Client--------------------------#
2 | spring.config.import=optional:configserver:http://localhost:8888
3 | spring.cloud.config.profile=local
4 |
5 | #------------------------Live Reload --------------------------#
6 | spring.devtools.livereload.port=35730
7 |
8 | #------------------------Logging --------------------------#
9 | logging.level.org.springframework.cloud.gateway=DEBUG
10 | logging.level.org.springframework.security=DEBUG
11 | logging.level.org.springframework.web.reactive.function.client=DEBUG
12 |
13 | #------------------------Actuator --------------------------#
14 | management.endpoints.web.exposure.include=health,info
15 | management.endpoint.health.enabled=true
16 | management.endpoint.health.probes.enabled=true
--------------------------------------------------------------------------------
/api-gateway/src/main/resources/application-prod.properties:
--------------------------------------------------------------------------------
1 | #------------------------Config Client--------------------------#
2 | spring.config.import=optional:configserver:http://config:8888
3 | spring.cloud.config.profile=prod
4 | spring.cloud.config.fail-fast=true
5 | spring.cloud.config.request-connect-timeout=30000
6 | spring.cloud.config.request-read-timeout=360000
--------------------------------------------------------------------------------
/api-gateway/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 | #----------------------------App Props---------------------------------------------#
2 | spring.application.name=api-gateway
3 | server.port=8755
4 |
5 | #----------------------------Active Profile----------------------------------------#
6 | spring.profiles.active=@activatedProperties@
7 |
8 | #----------------------------show IP address---------------------------------------#
9 | eureka.instance.prefer-ip-address=true
10 | eureka.instance.instance-id=${spring.cloud.client.ip-address}:${server.port}
11 | eureka.instance.hostname=${spring.cloud.client.ip-address}
12 |
13 | spring.main.allow-bean-definition-overriding=true
14 |
15 | spring.cloud.gateway.discovery.locator.enabled=true
16 | spring.cloud.gateway.discovery.locator.lower-case-service-id=true
--------------------------------------------------------------------------------
/api-gateway/src/main/resources/config.properties:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubaid4j/Cloud-Native-App-Spring-Boot/d023b0a732b43f4196176cd9fa3a67490a79eaab/api-gateway/src/main/resources/config.properties
--------------------------------------------------------------------------------
/audit/.dockerignore:
--------------------------------------------------------------------------------
1 | .gitignore
2 | audit.iml
3 | Dockerfile
4 | Dockerfile.multistage
5 | /target
--------------------------------------------------------------------------------
/audit/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 | !**/src/main/**/target/
5 | !**/src/test/**/target/
6 |
7 | ### STS ###
8 | .apt_generated
9 | .classpath
10 | .factorypath
11 | .project
12 | .settings
13 | .springBeans
14 | .sts4-cache
15 |
16 | ### IntelliJ IDEA ###
17 | .idea
18 | *.iws
19 | *.iml
20 | *.ipr
21 |
22 | ### NetBeans ###
23 | /nbproject/private/
24 | /nbbuild/
25 | /dist/
26 | /nbdist/
27 | /.nb-gradle/
28 | build/
29 | !**/src/main/**/build/
30 | !**/src/test/**/build/
31 |
32 | ### VS Code ###
33 | .vscode/
34 |
--------------------------------------------------------------------------------
/audit/Dockerfile.multistage:
--------------------------------------------------------------------------------
1 | ARG APP_VERSION
2 | FROM ubaidurehman/3cn-parent:${APP_VERSION} as build
3 | LABEL maintainer="urehman.bese16seecs@seecs.edu.pk"
4 | VOLUME /tmp
5 | WORKDIR /
6 | ADD . .
7 | RUN mvn clean install -DskipTests
8 |
9 | FROM openjdk:17-slim
10 | VOLUME /tmp
11 | WORKDIR /
12 | EXPOSE 8950
13 | ARG APP_VERSION
14 | COPY --from=build /target/audit-${APP_VERSION}.jar service.jar
15 | ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-Dspring.profiles.active=dev","-jar","/service.jar"]
16 |
--------------------------------------------------------------------------------
/audit/readme.md:
--------------------------------------------------------------------------------
1 | About
2 | =====
3 | - [Audit Service](http://localhost:8755/swagger-ui/index.html?urls.primaryName=audit)
4 |
5 | Dependencies
6 | ============
7 | - #### Web (Reactor Netty as the embedded reactive HTTP server + web flux)
8 | - spring-boot-starter-webflux
9 | - #### Data
10 | - spring-boot-starter-data-r2dbc
11 | - r2dbc-mysql
12 | - mysql-connector-java
13 | - #### Cloud
14 | - ##### Config Client
15 | - spring-cloud-starter-config
16 | - ##### Naming Server Client
17 | - spring-cloud-starter-netflix-eureka-client
18 | - ##### Distributed Tracing
19 | - spring-cloud-sleuth-zipkin
20 | - spring-cloud-starter-sleuth
21 | - #### Messaging
22 | - #### AMQP (Spring AMQP and Rabbit MQ)
23 | - #### Security
24 | - ##### Spring Security
25 | - spring-cloud-starter-security
26 | - ##### [OAuth2 Resource Server](./../moreinfo.md#Resource-server)
27 | - spring-boot-starter-oauth2-resource-server
28 | - #### AOP
29 | - spring-boot-starter-aop
30 | - #### Logstash (Sending logs to Logstash)
31 | - reactive-logstash-logging-spring-boot-starter
32 | - ### Database Migration (Custom Implementation)
33 | - r2dbc-migrate-spring-boot-starter
34 | - #### [Dependencies From Parent](./../moreinfo.md#Dependencies-from-parent)
35 |
36 | [Distributed Tracing](./../moreinfo.md#distributed-tracing)
37 | -----------------------------------------------------------
38 | [ELK Stack](./../moreinfo.md#elk-stack)
39 | ---------------------------------------
40 | [Audience Validation](./../moreinfo.md#audience-validation)
41 | ------------------------
--------------------------------------------------------------------------------
/audit/src/main/java/com/ubaid/ms/AuditApplication.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
6 | import org.springframework.web.reactive.config.EnableWebFlux;
7 |
8 | @SpringBootApplication
9 | @EnableDiscoveryClient
10 | @EnableWebFlux
11 | public class AuditApplication {
12 |
13 | public static void main(String[] args) {
14 | SpringApplication.run(AuditApplication.class, args);
15 | }
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/audit/src/main/java/com/ubaid/ms/audit/config/Beans.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.audit.config;
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper;
4 | import org.springframework.beans.factory.config.ConfigurableBeanFactory;
5 | import org.springframework.context.annotation.Bean;
6 | import org.springframework.context.annotation.Scope;
7 |
8 | public class Beans {
9 |
10 | @Bean
11 | @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
12 | public ObjectMapper objectMapper() {
13 | return new ObjectMapper();
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/audit/src/main/java/com/ubaid/ms/audit/config/MessageBrokerConfig.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.audit.config;
2 |
3 | import org.springframework.amqp.core.Queue;
4 | import org.springframework.context.annotation.Bean;
5 | import org.springframework.context.annotation.Configuration;
6 |
7 | import static com.ubaid.ms.common.util.Constants.AUDIT_QUEUE;
8 |
9 | @Configuration
10 | public class MessageBrokerConfig {
11 |
12 | @Bean
13 | public Queue auditQueue() {
14 | return new Queue(AUDIT_QUEUE, false);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/audit/src/main/java/com/ubaid/ms/audit/controller/InfoController.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.audit.controller;
2 |
3 | import com.ubaid.ms.audit.service.InfoService;
4 | import com.ubaid.ms.common.dto.serviceinfo.ServiceInformation;
5 | import lombok.RequiredArgsConstructor;
6 | import org.springframework.http.ResponseEntity;
7 | import org.springframework.web.bind.annotation.GetMapping;
8 | import org.springframework.web.bind.annotation.RequestMapping;
9 | import org.springframework.web.bind.annotation.RestController;
10 |
11 | @RestController
12 | @RequestMapping("v1")
13 | @RequiredArgsConstructor
14 | public class InfoController {
15 | private final InfoService infoService;
16 |
17 | @GetMapping("info")
18 | public ResponseEntity getInfo() {
19 | return ResponseEntity.ok(infoService.get());
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/audit/src/main/java/com/ubaid/ms/audit/dao/AuditDAO.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.audit.dao;
2 |
3 | import com.ubaid.ms.audit.entity.Audit;
4 | import org.springframework.data.r2dbc.repository.Query;
5 | import org.springframework.data.r2dbc.repository.R2dbcRepository;
6 | import reactor.core.publisher.Flux;
7 | import reactor.core.publisher.Mono;
8 |
9 | public interface AuditDAO extends R2dbcRepository {
10 | Flux findAllByUserUuid(String userUUID);
11 |
12 | @Query(value = "UPDATE audit SET is_deleted=true WHERE id = :id")
13 | Mono delete(Long id);
14 | }
15 |
--------------------------------------------------------------------------------
/audit/src/main/java/com/ubaid/ms/audit/entity/Audit.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.audit.entity;
2 |
3 | import lombok.Data;
4 | import org.springframework.data.annotation.Id;
5 | import org.springframework.data.relational.core.mapping.Table;
6 |
7 | import java.time.Instant;
8 |
9 | @Data
10 | @Table
11 | public class Audit {
12 |
13 | @Id
14 | private Long id;
15 | private String userUuid;
16 | private Instant createdAt;
17 | private String fromCurrency;
18 | private String toCurrency;
19 | private double exchangeRate;
20 | private double fromCurrencyValue;
21 | private double toCurrencyValue;
22 | private String userIPAddress;
23 | private String currencyExchangeURL;
24 | private String currencyConversionURL;
25 | private int currencyExchangePort;
26 | private int currencyConversionPort;
27 | private boolean isDeleted;
28 | private Instant lastUpdated;
29 | }
30 |
--------------------------------------------------------------------------------
/audit/src/main/java/com/ubaid/ms/audit/service/AuditService.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.audit.service;
2 |
3 | import com.ubaid.ms.audit.entity.Audit;
4 | import reactor.core.publisher.Flux;
5 | import reactor.core.publisher.Mono;
6 |
7 | import java.security.Principal;
8 |
9 | public interface AuditService {
10 | Mono findById(Long id);
11 | Flux findAllByUserUUID(Principal principal);
12 | Flux findAll();
13 | Mono save(Principal principal, Audit audit);
14 | Mono update(Principal principal, Audit audit);
15 | void save(Audit audit);
16 | Mono delete(Long id);
17 | }
18 |
--------------------------------------------------------------------------------
/audit/src/main/java/com/ubaid/ms/audit/service/InfoService.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.audit.service;
2 |
3 | import com.ubaid.ms.common.dto.serviceinfo.ServiceInformation;
4 |
5 | public interface InfoService {
6 | ServiceInformation get();
7 | }
8 |
--------------------------------------------------------------------------------
/audit/src/main/java/com/ubaid/ms/audit/service/InfoServiceImpl.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.audit.service;
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper;
4 | import com.netflix.appinfo.ApplicationInfoManager;
5 | import com.ubaid.ms.common.dto.serviceinfo.ServiceInformation;
6 | import com.ubaid.ms.common.dto.serviceinfo.ServiceInformationBuilder;
7 | import lombok.RequiredArgsConstructor;
8 | import lombok.extern.slf4j.Slf4j;
9 | import org.springframework.boot.actuate.info.InfoEndpoint;
10 | import org.springframework.stereotype.Service;
11 |
12 | @Service
13 | @Slf4j
14 | @RequiredArgsConstructor
15 | public class InfoServiceImpl implements InfoService {
16 |
17 | private final InfoEndpoint infoEndpoint;
18 | private final ObjectMapper objectMapper;
19 | private final ApplicationInfoManager applicationInfoManager;
20 |
21 | @Override
22 | public ServiceInformation get() {
23 | ServiceInformationBuilder builder = ServiceInformationBuilder
24 | .builder(objectMapper.convertValue(infoEndpoint.info(), ServiceInformation.class));
25 | builder.name(applicationInfoManager.getInfo().getAppName());
26 | ServiceInformation serviceInformation = builder.build();
27 | log.debug("Service Information: {}", serviceInformation);
28 | return serviceInformation;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/audit/src/main/resources/application-dev.properties:
--------------------------------------------------------------------------------
1 | #------------------------Config Client--------------------------#
2 | spring.config.import=optional:configserver:http://config:8888
3 | spring.cloud.config.profile=dev
4 | spring.cloud.config.fail-fast=true
5 | spring.cloud.config.request-connect-timeout=30000
6 | spring.cloud.config.request-read-timeout=360000
--------------------------------------------------------------------------------
/audit/src/main/resources/application-local.properties:
--------------------------------------------------------------------------------
1 | #------------------------Config Client--------------------------#
2 | spring.config.import=optional:configserver:http://localhost:8888
3 | spring.cloud.config.profile=local
4 |
5 | #------------------------Live Reload --------------------------#
6 | spring.devtools.livereload.port=35731
7 |
8 |
9 | #------------------------Logs --------------------------#
10 | logging.level.org.springframework.security=DEBUG
11 | logging.level.org.springframework.web.reactive.function.client=DEBUG
12 | logging.level.com.ubaid.ms.auditservice=DEBUG
13 | logging.level.name.nkonev.r2dbc=DEBUG
14 | logging.level.com.ubaid.ms=TRACE
15 |
16 | #------------------------Actuator --------------------------#
17 | management.endpoints.web.exposure.include=health,info
18 | management.endpoint.health.enabled=true
19 | management.endpoint.health.probes.enabled=true
20 |
--------------------------------------------------------------------------------
/audit/src/main/resources/application-prod.properties:
--------------------------------------------------------------------------------
1 | #------------------------Config Client--------------------------#
2 | spring.config.import=optional:configserver:http://config:8888
3 | spring.cloud.config.profile=prod
4 | spring.cloud.config.fail-fast=true
5 | spring.cloud.config.request-connect-timeout=30000
6 | spring.cloud.config.request-read-timeout=360000
--------------------------------------------------------------------------------
/audit/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 | #----------------------------SApplication config-----------------------------------#
2 | spring.application.name=audit
3 | server.port=8950
4 |
5 | #----------------------------Active Profile----------------------------------------#
6 | spring.profiles.active=@activatedProperties@
7 |
8 | #----------------------------Static IP---------------------------------------------#
9 | eureka.instance.prefer-ip-address=true
10 | eureka.instance.instance-id=${spring.cloud.client.ip-address}:${server.port}
11 | eureka.instance.hostname=${spring.cloud.client.ip-address}
12 |
--------------------------------------------------------------------------------
/audit/src/main/resources/config.properties:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubaid4j/Cloud-Native-App-Spring-Boot/d023b0a732b43f4196176cd9fa3a67490a79eaab/audit/src/main/resources/config.properties
--------------------------------------------------------------------------------
/audit/src/main/resources/db/migration/V1__gh_301_create_audit_table.sql:
--------------------------------------------------------------------------------
1 | create table audit (
2 | id bigint primary key auto_increment,
3 | created_at timestamp,
4 | currency_conversion_port int,
5 | currency_conversion_url varchar(255),
6 | currency_exchange_port int,
7 | currency_exchange_url varchar(255),
8 | exchange_rate float,
9 | from_currency varchar(255),
10 | from_currency_value float,
11 | to_currency varchar(255),
12 | to_currency_value float,
13 | is_deleted boolean,
14 | last_updated timestamp,
15 | user_ip_address varchar(255),
16 | user_uuid varchar(255)
17 | )
--------------------------------------------------------------------------------
/audit/src/main/resources/db/migration/V2__gh_360_replace_float_with_double.sql:
--------------------------------------------------------------------------------
1 | alter table audit
2 | modify column exchange_rate double;
3 |
4 | alter table audit
5 | modify column from_currency_value double;
6 |
7 | alter table audit
8 | modify column to_currency_value double;
9 |
--------------------------------------------------------------------------------
/audit/src/test/java/com/ubaid/ms/auditservice/AuditApplicationTests.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.auditservice;
2 |
3 | import org.junit.jupiter.api.Test;
4 | import org.springframework.boot.test.context.SpringBootTest;
5 |
6 | @SpringBootTest
7 | class AuditApplicationTests {
8 |
9 | @Test
10 | void contextLoads() {
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/build-3cn-parent-image.sh:
--------------------------------------------------------------------------------
1 | docker build -t ubaidurehman/3cn-parent:0.0.3-SNAPSHOT -f Dockerfile.3cn-parent-init .
--------------------------------------------------------------------------------
/build-all-microservice-images.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | declare -a microservices=("api-gateway" "audit" "config" "country" "currency-conversion" "currency-exchange" "discovery" "math" "user")
3 | APP_VERSION=0.0.3-SNAPSHOT
4 | for microservice in "${microservices[@]}"
5 | do
6 | echo buidling image of "$microservice"
7 | mvn spring-boot:build-image -DskipTests -f "$microservice"
8 | echo tagging "$microservice":$APP_VERSION to ubaidurehman/"$microservice":$APP_VERSION
9 | docker tag "$microservice":$APP_VERSION ubaidurehman/"$microservice":$APP_VERSION
10 | done
--------------------------------------------------------------------------------
/clients/3cn-react-client/.dockerignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .idea
3 | *.drawio
4 | .gitignore
--------------------------------------------------------------------------------
/clients/3cn-react-client/.env.dev:
--------------------------------------------------------------------------------
1 | REACT_APP_ENV=dev
--------------------------------------------------------------------------------
/clients/3cn-react-client/.env.prod:
--------------------------------------------------------------------------------
1 | REACT_APP_ENV=prod
--------------------------------------------------------------------------------
/clients/3cn-react-client/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "es2021": true,
5 | "node": true
6 | },
7 | "extends": [
8 | "eslint:recommended",
9 | "plugin:react/recommended"
10 | ],
11 | "parserOptions": {
12 | "ecmaFeatures": {
13 | "jsx": true
14 | },
15 | "ecmaVersion": 12,
16 | "sourceType": "module"
17 | },
18 | "plugins": [
19 | "react"
20 | ],
21 | "rules": {
22 | "indent": [
23 | "error",
24 | 4
25 | ],
26 | "linebreak-style": [
27 | "error",
28 | "unix"
29 | ],
30 | "quotes": [
31 | "error",
32 | "single"
33 | ],
34 | "semi": [
35 | "error",
36 | "always"
37 | ]
38 | },
39 | "settings": {
40 | "react" : {
41 | "version": "latest"
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/clients/3cn-react-client/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
25 | package-lock.json
26 |
--------------------------------------------------------------------------------
/clients/3cn-react-client/Dockerfile:
--------------------------------------------------------------------------------
1 | #To build image: docker run -t 3cn-fe:{version} --build-arg ENV={env} .
2 | FROM node:14.17.3-alpine as build
3 | WORKDIR /app
4 | ENV PATH /app/node_modules/.bin:$PATH
5 | COPY package.json ./
6 | RUN npm install
7 | COPY . ./
8 | ARG ENV
9 | RUN npm run build:${ENV}
10 |
11 | # production environment
12 | FROM nginx:stable-alpine
13 | COPY --from=build /app/build /usr/share/nginx/html
14 | # new
15 | COPY nginx/nginx.conf /etc/nginx/conf.d/default.conf
16 | EXPOSE 80
17 | CMD ["nginx", "-g", "daemon off;"]
--------------------------------------------------------------------------------
/clients/3cn-react-client/README.md:
--------------------------------------------------------------------------------
1 | Stay Tuned
2 | ==========
3 |
4 |
5 | # Notes:
6 | - ### ES LINT
7 | - To add Linting: ```eslint --init```
8 | - To lint through all .js files: ```eslint . --ext .js```
9 |
--------------------------------------------------------------------------------
/clients/3cn-react-client/build-push-prod-ui-image.sh:
--------------------------------------------------------------------------------
1 | docker build -t ubaidurehman/3cn-fe:0.0.3-SNAPSHOT --build-arg ENV=prod .
2 | docker push ubaidurehman/3cn-fe:0.0.3-SNAPSHOT
--------------------------------------------------------------------------------
/clients/3cn-react-client/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": "src"
4 | },
5 | "include": [
6 | "src"
7 | ]
8 | }
9 |
--------------------------------------------------------------------------------
/clients/3cn-react-client/nginx/nginx.conf:
--------------------------------------------------------------------------------
1 | server {
2 |
3 | listen 80;
4 |
5 | location / {
6 | root /usr/share/nginx/html;
7 | index index.html index.htm;
8 | try_files $uri $uri/ /index.html;
9 | }
10 |
11 | error_page 500 502 503 504 /50x.html;
12 |
13 | location = /50x.html {
14 | root /usr/share/nginx/html;
15 | }
16 |
17 | }
--------------------------------------------------------------------------------
/clients/3cn-react-client/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubaid4j/Cloud-Native-App-Spring-Boot/d023b0a732b43f4196176cd9fa3a67490a79eaab/clients/3cn-react-client/public/favicon.ico
--------------------------------------------------------------------------------
/clients/3cn-react-client/public/keycloak-dev.json:
--------------------------------------------------------------------------------
1 | {
2 | "realm": "3cn",
3 | "auth-server-url": "http://auth-server:9999/auth/",
4 | "ssl-required": "external",
5 | "resource": "3cn-react-client",
6 | "public-client": true,
7 | "confidential-port": 0
8 | }
9 |
--------------------------------------------------------------------------------
/clients/3cn-react-client/public/keycloak-local.json:
--------------------------------------------------------------------------------
1 | {
2 | "realm": "3cn",
3 | "auth-server-url": "http://localhost:9999/auth/",
4 | "ssl-required": "external",
5 | "resource": "3cn-react-client",
6 | "public-client": true,
7 | "confidential-port": 0
8 | }
9 |
--------------------------------------------------------------------------------
/clients/3cn-react-client/public/keycloak-prod.json:
--------------------------------------------------------------------------------
1 | {
2 | "realm": "3cn",
3 | "auth-server-url": "http://auth-server-io/auth",
4 | "ssl-required": "external",
5 | "resource": "3cn-react-client",
6 | "public-client": true,
7 | "confidential-port": 0
8 | }
9 |
--------------------------------------------------------------------------------
/clients/3cn-react-client/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubaid4j/Cloud-Native-App-Spring-Boot/d023b0a732b43f4196176cd9fa3a67490a79eaab/clients/3cn-react-client/public/logo192.png
--------------------------------------------------------------------------------
/clients/3cn-react-client/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubaid4j/Cloud-Native-App-Spring-Boot/d023b0a732b43f4196176cd9fa3a67490a79eaab/clients/3cn-react-client/public/logo512.png
--------------------------------------------------------------------------------
/clients/3cn-react-client/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/clients/3cn-react-client/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/clients/3cn-react-client/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
--------------------------------------------------------------------------------
/clients/3cn-react-client/src/App.js:
--------------------------------------------------------------------------------
1 | import 'App.css';
2 | import React, {Suspense} from 'react';
3 | import {Route, Switch} from 'react-router';
4 | import Layout from 'hoc/Layout/Layout';
5 | import CurrencyConverter from 'container/CurrencyConverter/CurrencyConverter';
6 | import UserInfo from 'component/userinfo/UserInfo';
7 | import ServiceDown from 'component/down/ServiceDown';
8 | import ProtectedRoute from 'util/ProtectedRoute';
9 | import Authenticate from 'component/auth/Authenticate';
10 | import {ReactKeycloakProvider} from '@react-keycloak/web';
11 | import keycloak from 'keycloak';
12 |
13 | const App = () => {
14 |
15 | let routes = (
16 |
17 | Loading.....
}>
18 |
19 |
20 |
21 |
22 |
23 |
24 | );
25 |
26 | return (
27 |
28 |
29 |
30 | {routes}
31 |
32 |
33 |
34 | );
35 | };
36 | export default App;
37 |
--------------------------------------------------------------------------------
/clients/3cn-react-client/src/component/auth/Authenticate.js:
--------------------------------------------------------------------------------
1 | import React, {useCallback} from 'react';
2 | import {useKeycloak} from '@react-keycloak/web';
3 | import {Redirect} from 'react-router-dom';
4 | import {useDispatch} from 'react-redux';
5 | import {AddAccessToken} from 'store/actions/AuthAction';
6 |
7 | const Authenticate = () => {
8 |
9 | const {initialized, keycloak} = useKeycloak();
10 | const dispatch = useDispatch();
11 | const addAccessToken = useCallback((accessToken) => dispatch(AddAccessToken(accessToken)), []);
12 |
13 | if (initialized && keycloak && !keycloak.authenticated) {
14 | console.log('In Authenticate: Login called');
15 | keycloak.login();
16 | }
17 |
18 | if (!initialized || !keycloak || !keycloak.authenticated) {
19 | return (
20 |
21 | Authenticating, please wait....
22 |
23 | );
24 | }
25 |
26 | if (initialized && keycloak && keycloak.authenticated) {
27 | console.log('-----------------------In Authenticate--------------- Adding access token in state');
28 | addAccessToken(keycloak.token);
29 |
30 | return (
31 |
32 | );
33 | }
34 | };
35 |
36 | export default Authenticate;
37 |
--------------------------------------------------------------------------------
/clients/3cn-react-client/src/component/convertionPaper/ConversionPaper.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import React from 'react';
3 | import {Container, Typography} from '@material-ui/core';
4 |
5 | const ConversionPaper = ({fromCountry, toCountry, convertedAmount}) => {
6 | return (
7 |
8 | {fromCountry ? fromCountry.currencyName + ' ' + fromCountry.country + '(' + fromCountry.currencyCode + ')' : ''} to {toCountry ? toCountry.currencyName + ' ' + toCountry.country + '(' + toCountry.currencyCode + ')' : ''}
9 |
10 | The Converted Amount is: {convertedAmount ? convertedAmount.exchangedCurrencyQuantity : ''}
11 |
12 | );
13 | };
14 |
15 | export default ConversionPaper;
16 |
17 | ConversionPaper.propTypes = {
18 | fromCountry : PropTypes.object,
19 | toCountry : PropTypes.object,
20 | convertedAmount: PropTypes.object
21 | };
22 |
23 |
--------------------------------------------------------------------------------
/clients/3cn-react-client/src/component/down/ServiceDown.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | const ServiceDown = () => {
3 | return (
4 | <>
5 | Service is Down. Sorry for inconvenience
6 | >
7 | );
8 | };
9 | export default ServiceDown;
10 |
--------------------------------------------------------------------------------
/clients/3cn-react-client/src/component/footer/Footer.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { makeStyles } from '@material-ui/core/styles';
3 | import BottomNavigation from '@material-ui/core/BottomNavigation';
4 | import BottomNavigationAction from '@material-ui/core/BottomNavigationAction';
5 | import InfoIcon from '@material-ui/icons/Info';
6 | import RestoreIcon from '@material-ui/icons/Restore';
7 |
8 | const useStyles = makeStyles({
9 | root: {
10 | flexGrow: 1,
11 | width: '100%',
12 | position: 'fixed',
13 | bottom: 0
14 | },
15 | });
16 |
17 |
18 | const Footer = () => {
19 |
20 | const classes = useStyles();
21 | const [value, setValue] = React.useState('Recents');
22 |
23 | const handleChange = (event, newValue) => {
24 | setValue(newValue);
25 | };
26 | return (
27 |
28 | } />
29 | } />
30 |
31 | );
32 | };
33 | export default Footer;
34 |
--------------------------------------------------------------------------------
/clients/3cn-react-client/src/component/userinfo/UserInfo.js:
--------------------------------------------------------------------------------
1 | import {useKeycloak} from '@react-keycloak/web';
2 | import React from 'react';
3 |
4 | const UserInfo = () => {
5 | const { keycloak, initialized } = useKeycloak();
6 |
7 | if (keycloak && initialized && keycloak.authenticated) {
8 | return (
9 |
10 | Hello {keycloak.tokenParsed.preferred_username}
11 |
14 |
15 | );
16 | }
17 | };
18 | export default UserInfo;
19 |
--------------------------------------------------------------------------------
/clients/3cn-react-client/src/hoc/Layout/Layout.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import CssBaseline from '@material-ui/core/CssBaseline';
3 | import Container from '@material-ui/core/Container';
4 | import PropTypes from 'prop-types';
5 | import Header from 'component/header/Header';
6 | import Footer from 'component/footer/Footer';
7 |
8 | const Layout = props => {
9 | return (
10 | <>
11 |
12 |
13 |
14 | {props.children}
15 |
16 |
17 | >
18 | );
19 | };
20 | export default Layout;
21 |
22 | Layout.propTypes = {
23 | children: PropTypes.any
24 | };
25 |
26 |
--------------------------------------------------------------------------------
/clients/3cn-react-client/src/http/RequestHandler.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 |
3 |
4 | const env = process.env.REACT_APP_ENV;
5 | let baseURL;
6 | if (env === 'prod') {
7 | baseURL = 'http://currency-converter.api-gateway.io';
8 | } else {
9 | baseURL = 'http://localhost:8755';
10 | }
11 |
12 | const RequestHandler = axios.create({
13 | baseURL: baseURL,
14 | headers: {
15 | 'Access-Control-Allow-Origin': '*',
16 | 'Content-Type': 'application/json',
17 | }
18 | });
19 | export default RequestHandler;
20 |
--------------------------------------------------------------------------------
/clients/3cn-react-client/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
5 | sans-serif;
6 | -webkit-font-smoothing: antialiased;
7 | -moz-osx-font-smoothing: grayscale;
8 | }
9 |
10 | code {
11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
12 | monospace;
13 | }
14 |
--------------------------------------------------------------------------------
/clients/3cn-react-client/src/keycloak.js:
--------------------------------------------------------------------------------
1 | import Keycloak from 'keycloak-js';
2 | // Setup Keycloak instance as needed
3 | // Pass initialization options as required or leave blank to load from 'keycloak-dev.json'
4 | const env = process.env.REACT_APP_ENV;
5 | console.log('-----------Environment---------------: ', env);
6 | let keycloakPath;
7 | let redirectUri;
8 | if (env === 'dev') {
9 | keycloakPath = 'keycloak-dev.json';
10 | redirectUri = 'http://localhost:3000';
11 | } else if (env === 'prod') {
12 | keycloakPath = 'keycloak-prod.json';
13 | redirectUri = 'http://currency-converter.io/';
14 | } else {
15 | keycloakPath = 'keycloak-local.json';
16 | redirectUri = 'http://localhost:3000';
17 | }
18 |
19 | const kc = new Keycloak(keycloakPath);
20 | kc.redirectUri=redirectUri;
21 |
22 | export default kc;
23 |
--------------------------------------------------------------------------------
/clients/3cn-react-client/src/reportWebVitals.js:
--------------------------------------------------------------------------------
1 | const reportWebVitals = onPerfEntry => {
2 | if (onPerfEntry && onPerfEntry instanceof Function) {
3 | import('web-vitals').then(({getCLS, getFID, getFCP, getLCP, getTTFB}) => {
4 | getCLS(onPerfEntry);
5 | getFID(onPerfEntry);
6 | getFCP(onPerfEntry);
7 | getLCP(onPerfEntry);
8 | getTTFB(onPerfEntry);
9 | });
10 | }
11 | };
12 |
13 | export default reportWebVitals;
14 |
--------------------------------------------------------------------------------
/clients/3cn-react-client/src/setupTests.js:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import '@testing-library/jest-dom';
6 |
--------------------------------------------------------------------------------
/clients/3cn-react-client/src/store/ActionTypes.js:
--------------------------------------------------------------------------------
1 | export const POPULATE_COUNTRIES_START = 'POPULATE_COUNTRIES_START';
2 | export const POPULATE_COUNTRIES_FINISHED = 'POPULATE_COUNTRIES_FINISHED';
3 | export const POPULATE_COUNTRIES_ERROR = 'POPULATE_COUNTRIES_ERROR';
4 |
5 | export const SELECT_TO_COUNTRY = 'SELECT_TO_COUNTRY';
6 | export const SELECT_FROM_COUNTRY = 'SELECT_FROM_COUNTRY';
7 |
8 | export const CONVERT_CURRENCY_START = 'CONVERT_CURRENCY_START';
9 | export const CONVERT_CURRENCY_COMPLETE = 'CONVERT_CURRENCY_COMPLETE';
10 | export const CONVERT_CURRENCY_ERROR = 'CONVERT_CURRENCY_ERROR';
11 |
12 | export const ADD_ACCESS_TOKEN = 'ADD_ACCESS_TOKEN';
13 |
--------------------------------------------------------------------------------
/clients/3cn-react-client/src/store/actions/AuthAction.js:
--------------------------------------------------------------------------------
1 | import {ADD_ACCESS_TOKEN} from 'store/ActionTypes';
2 |
3 | export const AddAccessToken = (accessToken) => {
4 | return {
5 | type: ADD_ACCESS_TOKEN,
6 | accessToken: accessToken
7 | };
8 | };
9 |
--------------------------------------------------------------------------------
/clients/3cn-react-client/src/store/actions/ConvertCurrencyAction.js:
--------------------------------------------------------------------------------
1 | import {
2 | CONVERT_CURRENCY_START,
3 | CONVERT_CURRENCY_COMPLETE,
4 | CONVERT_CURRENCY_ERROR
5 | } from 'store/ActionTypes';
6 |
7 | import RequestHandler from 'http/RequestHandler';
8 |
9 | export const ConvertCurrency = ({fromCountryCode, toCountryCode, amount, accessToken}) => {
10 | let config = {
11 | headers: {
12 | 'Authorization': 'Bearer ' + accessToken,
13 | }
14 | };
15 | return dispatch => {
16 | dispatch(convertCurrencyStart());
17 | RequestHandler.get(`currency-conversion/v1/${fromCountryCode}/to/${toCountryCode}/q/${amount}`, config)
18 | .then(res => {
19 | console.log(res);
20 | dispatch(convertCurrencyComplete(res.data));
21 | })
22 | .catch(err => {
23 | console.log(err);
24 | dispatch(convertCurrencyError(err));
25 | });
26 | };
27 | };
28 |
29 | const convertCurrencyStart = () => {
30 | return {
31 | type: CONVERT_CURRENCY_START
32 | };
33 | };
34 |
35 | const convertCurrencyComplete = (data) => {
36 | return {
37 | type: CONVERT_CURRENCY_COMPLETE,
38 | data: data
39 | };
40 | };
41 |
42 | const convertCurrencyError = (error) => {
43 | return {
44 | type: CONVERT_CURRENCY_ERROR,
45 | error: error
46 | };
47 | };
48 |
--------------------------------------------------------------------------------
/clients/3cn-react-client/src/store/actions/PopulateCountryAction.js:
--------------------------------------------------------------------------------
1 | import {
2 | POPULATE_COUNTRIES_ERROR,
3 | POPULATE_COUNTRIES_FINISHED,
4 | POPULATE_COUNTRIES_START
5 | } from 'store/ActionTypes';
6 | import RequestHandler from 'http/RequestHandler';
7 |
8 | export const PopulateCountryCodes = (accessToken) => {
9 |
10 | let config = {
11 | headers: {
12 | 'Authorization': 'Bearer ' + accessToken,
13 | }
14 | };
15 |
16 | return dispatch => {
17 | dispatch(populateCountryCodeStart());
18 | RequestHandler.get('country/v1/code', config)
19 | .then(res => {
20 | console.log(res);
21 | dispatch(populateCountryFinished(res.data));
22 | })
23 | .catch(err => {
24 | console.log(err);
25 | dispatch(error());
26 | });
27 | };
28 | };
29 |
30 | const populateCountryFinished = (countries) => {
31 | return {
32 | type: POPULATE_COUNTRIES_FINISHED,
33 | countries: countries
34 | };
35 | };
36 |
37 | const populateCountryCodeStart = () => {
38 | console.log('Populating Country Codes Start');
39 | return {
40 | type: POPULATE_COUNTRIES_START
41 | };
42 | };
43 |
44 | const error = () => {
45 | console.log('There is some error in populating country codes');
46 | return {
47 | type: POPULATE_COUNTRIES_ERROR
48 | };
49 | };
50 |
--------------------------------------------------------------------------------
/clients/3cn-react-client/src/store/actions/SelectCountryAction.js:
--------------------------------------------------------------------------------
1 | import {SELECT_TO_COUNTRY, SELECT_FROM_COUNTRY} from 'store/ActionTypes';
2 |
3 | export const SelectFromCountry = (country) => {
4 | console.log('SelectFromCountry: country ----> ', country);
5 | return {
6 | type: SELECT_FROM_COUNTRY,
7 | country: country
8 | };
9 | };
10 |
11 | export const SelectToCountry = (country) => {
12 | console.log('SelectToCountry: country ----> ', country);
13 | return {
14 | type: SELECT_TO_COUNTRY,
15 | country: country
16 | };
17 | };
18 |
--------------------------------------------------------------------------------
/clients/3cn-react-client/src/store/reducers/AuthReducer.js:
--------------------------------------------------------------------------------
1 | import {ADD_ACCESS_TOKEN} from 'store/ActionTypes';
2 |
3 | const initialState = {
4 | accessToken: null
5 | };
6 |
7 | export const AuthReducer = (state = initialState, action) => {
8 | switch (action.type) {
9 | case ADD_ACCESS_TOKEN:
10 | return {...state, accessToken: action.accessToken};
11 | default:
12 | return state;
13 | }
14 | };
15 |
--------------------------------------------------------------------------------
/clients/3cn-react-client/src/store/reducers/ConvertCurrencyReducer.js:
--------------------------------------------------------------------------------
1 | import {
2 | CONVERT_CURRENCY_ERROR,
3 | CONVERT_CURRENCY_COMPLETE,
4 | CONVERT_CURRENCY_START
5 | } from 'store/ActionTypes';
6 |
7 | const initialState = {
8 | convertedData: null,
9 | loading: false,
10 | error: false
11 | };
12 |
13 | const ConvertCurrencyReducer = (state = initialState, action) => {
14 | switch (action.type) {
15 | case CONVERT_CURRENCY_COMPLETE:
16 | return {...state, convertedData: action.data, loading: false};
17 | case CONVERT_CURRENCY_START:
18 | return {...state, loading: true, error: false};
19 | case CONVERT_CURRENCY_ERROR:
20 | return {...state, loading: false, error: true};
21 | default:
22 | return state;
23 | }
24 | };
25 | export default ConvertCurrencyReducer;
26 |
--------------------------------------------------------------------------------
/clients/3cn-react-client/src/store/reducers/PopulateCountryReducer.js:
--------------------------------------------------------------------------------
1 | import {
2 | POPULATE_COUNTRIES_ERROR,
3 | POPULATE_COUNTRIES_FINISHED,
4 | POPULATE_COUNTRIES_START
5 | } from 'store/ActionTypes';
6 |
7 | const initialState = {
8 | countries: [],
9 | error: null,
10 | loading: false
11 | };
12 |
13 | const PopulateCountryReducer = (state = initialState, action) => {
14 |
15 | switch (action.type) {
16 | case POPULATE_COUNTRIES_FINISHED:
17 | return {...state, countries: action.countries, error: false, loading: false};
18 | case POPULATE_COUNTRIES_START:
19 | return {...state, loading: true, error: false};
20 | case POPULATE_COUNTRIES_ERROR:
21 | return {...state, error: true, loading: false};
22 | default:
23 | return state;
24 | }
25 | };
26 | export default PopulateCountryReducer;
27 |
--------------------------------------------------------------------------------
/clients/3cn-react-client/src/store/reducers/SelectCountryReducer.js:
--------------------------------------------------------------------------------
1 | import {SELECT_FROM_COUNTRY, SELECT_TO_COUNTRY} from 'store/ActionTypes';
2 |
3 | const initialState = {
4 | fromCountry: null,
5 | toCountry: null
6 | };
7 |
8 | export const SelectCountryReducer = (state = initialState, action) => {
9 | switch (action.type) {
10 | case SELECT_FROM_COUNTRY:
11 | return {...state, fromCountry: action.country};
12 | case SELECT_TO_COUNTRY:
13 | return {...state, toCountry: action.country};
14 | default:
15 | return state;
16 | }
17 | };
18 |
--------------------------------------------------------------------------------
/clients/3cn-react-client/src/util/ProtectedRoute.js:
--------------------------------------------------------------------------------
1 | import { useKeycloak } from '@react-keycloak/web';
2 | import React from 'react';
3 | import { Redirect, Route } from 'react-router-dom';
4 | import PropTypes from 'prop-types';
5 |
6 |
7 | const ProtectedRoute = ({ component: Component, roles, ...rest }) => {
8 | const {initialized, keycloak} = useKeycloak();
9 |
10 | const isAuthorized = (roles) => {
11 | if (keycloak && roles) {
12 | const isAuth = roles.some(r => {
13 | const realm = keycloak.hasRealmRole(r);
14 | const resource = keycloak.hasResourceRole(r);
15 | return realm || resource;
16 | });
17 | console.log('Is Current User is Authorized: ------------------------------- ', isAuth);
18 | return isAuth;
19 | }
20 | return false;
21 | };
22 |
23 | if (initialized && keycloak && !keycloak.authenticated) {
24 | console.log('---------------------------Login called ----------------------------');
25 | keycloak.login();
26 | }
27 |
28 | return (
29 | {
32 | return isAuthorized(roles)
33 | ?
34 | : ;
35 | }}
36 | />
37 | );
38 | };
39 | ProtectedRoute.propTypes = {
40 | roles: PropTypes.any,
41 | component: PropTypes.any,
42 | };
43 | export default ProtectedRoute;
44 |
--------------------------------------------------------------------------------
/clients/CurrencyConversionReactNativeClient/.buckconfig:
--------------------------------------------------------------------------------
1 |
2 | [android]
3 | target = Google Inc.:Google APIs:23
4 |
5 | [maven_repositories]
6 | central = https://repo1.maven.org/maven2
7 |
--------------------------------------------------------------------------------
/clients/CurrencyConversionReactNativeClient/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | extends: '@react-native-community',
4 | };
5 |
--------------------------------------------------------------------------------
/clients/CurrencyConversionReactNativeClient/.gitattributes:
--------------------------------------------------------------------------------
1 | *.pbxproj -text
2 |
--------------------------------------------------------------------------------
/clients/CurrencyConversionReactNativeClient/.gitignore:
--------------------------------------------------------------------------------
1 | # OSX
2 | #
3 | .DS_Store
4 |
5 | # Xcode
6 | #
7 | build/
8 | *.pbxuser
9 | !default.pbxuser
10 | *.mode1v3
11 | !default.mode1v3
12 | *.mode2v3
13 | !default.mode2v3
14 | *.perspectivev3
15 | !default.perspectivev3
16 | xcuserdata
17 | *.xccheckout
18 | *.moved-aside
19 | DerivedData
20 | *.hmap
21 | *.ipa
22 | *.xcuserstate
23 |
24 | # Android/IntelliJ
25 | #
26 | build/
27 | .idea
28 | .gradle
29 | local.properties
30 | *.iml
31 |
32 | # node.js
33 | #
34 | node_modules/
35 | npm-debug.log
36 | yarn-error.log
37 |
38 | # BUCK
39 | buck-out/
40 | \.buckd/
41 | *.keystore
42 | !debug.keystore
43 |
44 | # fastlane
45 | #
46 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
47 | # screenshots whenever they are needed.
48 | # For more information about the recommended setup visit:
49 | # https://docs.fastlane.tools/best-practices/source-control/
50 |
51 | */fastlane/report.xml
52 | */fastlane/Preview.html
53 | */fastlane/screenshots
54 |
55 | # Bundle artifact
56 | *.jsbundle
57 |
58 | # CocoaPods
59 | /ios/Pods/
60 |
61 |
62 | android
63 | ios
--------------------------------------------------------------------------------
/clients/CurrencyConversionReactNativeClient/.prettierrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | bracketSpacing: false,
3 | jsxBracketSameLine: true,
4 | singleQuote: true,
5 | trailingComma: 'all',
6 | };
7 |
--------------------------------------------------------------------------------
/clients/CurrencyConversionReactNativeClient/.watchmanconfig:
--------------------------------------------------------------------------------
1 | {}
--------------------------------------------------------------------------------
/clients/CurrencyConversionReactNativeClient/App.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Sample React Native App
3 | * https://github.com/facebook/react-native
4 | *
5 | * @format
6 | * @flow strict-local
7 | */
8 |
9 | import React from 'react';
10 | import {Text} from 'react-native';
11 |
12 | const App: () => React$Node = () => {
13 | return (
14 | <>
15 | Hello World to Currency Conversion Service
16 | >
17 | );
18 | };
19 |
20 | export default App;
21 |
--------------------------------------------------------------------------------
/clients/CurrencyConversionReactNativeClient/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "CurrencyConversionReactNativeClient",
3 | "displayName": "CurrencyConversionReactNativeClient"
4 | }
--------------------------------------------------------------------------------
/clients/CurrencyConversionReactNativeClient/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: ['module:metro-react-native-babel-preset'],
3 | };
4 |
--------------------------------------------------------------------------------
/clients/CurrencyConversionReactNativeClient/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @format
3 | */
4 |
5 | import {AppRegistry} from 'react-native';
6 | import App from './App';
7 | import {name as appName} from './app.json';
8 |
9 | AppRegistry.registerComponent(appName, () => App);
10 |
--------------------------------------------------------------------------------
/clients/CurrencyConversionReactNativeClient/metro.config.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Metro configuration for React Native
3 | * https://github.com/facebook/react-native
4 | *
5 | * @format
6 | */
7 |
8 | module.exports = {
9 | transformer: {
10 | getTransformOptions: async () => ({
11 | transform: {
12 | experimentalImportSupport: false,
13 | inlineRequires: false,
14 | },
15 | }),
16 | },
17 | };
18 |
--------------------------------------------------------------------------------
/clients/CurrencyConversionReactNativeClient/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "CurrencyConversionReactNativeClient",
3 | "version": "0.0.1",
4 | "private": true,
5 | "scripts": {
6 | "android": "react-native run-android",
7 | "ios": "react-native run-ios",
8 | "start": "react-native start",
9 | "test": "jest",
10 | "lint": "eslint ."
11 | },
12 | "dependencies": {
13 | "react": "16.13.1",
14 | "react-native": "0.63.3"
15 | },
16 | "devDependencies": {
17 | "@babel/core": "^7.8.4",
18 | "@babel/runtime": "^7.8.4",
19 | "@react-native-community/eslint-config": "^1.1.0",
20 | "babel-jest": "^25.1.0",
21 | "eslint": "^6.5.1",
22 | "jest": "^25.1.0",
23 | "metro-react-native-babel-preset": "^0.59.0",
24 | "react-test-renderer": "16.13.1"
25 | },
26 | "jest": {
27 | "preset": "react-native"
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/common/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | /*/*.iml
--------------------------------------------------------------------------------
/common/dto/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | /target
--------------------------------------------------------------------------------
/common/dto/readme.md:
--------------------------------------------------------------------------------
1 | About
2 | =====
3 | 1. Module which contains the DTOs classes which are shared across the project.
--------------------------------------------------------------------------------
/common/dto/src/main/java/com/ubaid/ms/common/dto/AuditDTO.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.common.dto;
2 |
3 | import io.soabase.recordbuilder.core.RecordBuilder;
4 |
5 | import java.io.Serializable;
6 | import java.time.Instant;
7 |
8 | @RecordBuilder
9 | public record AuditDTO(
10 | Long id,
11 | String userUUID,
12 | Instant timestamp,
13 | String fromCurrency,
14 | String toCurrency,
15 | double exchangeRate,
16 | double fromCurrencyValue,
17 | double toCurrencyValue,
18 | String userIPAddress,
19 | String currencyExchangeIP,
20 | String currencyConversionIP,
21 | int currencyExchangePort,
22 | int currencyConversionPort
23 | ) implements Serializable { }
24 |
--------------------------------------------------------------------------------
/common/dto/src/main/java/com/ubaid/ms/common/dto/CountryCodeDTO.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.common.dto;
2 |
3 | import lombok.Data;
4 | import lombok.NoArgsConstructor;
5 |
6 | @Data
7 | @NoArgsConstructor
8 | public class CountryCodeDTO {
9 | private Long id;
10 | private String country;
11 | private String currencyName;
12 | private String currencyCode;
13 | private Integer number;
14 | private String isoCode;
15 | }
16 |
--------------------------------------------------------------------------------
/common/dto/src/main/java/com/ubaid/ms/common/dto/CurrencyInfoDTO.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.common.dto;
2 |
3 | import io.soabase.recordbuilder.core.RecordBuilder;
4 | import java.io.Serializable;
5 |
6 | @RecordBuilder
7 | public record CurrencyInfoDTO(String fromCurrency, String toCurrency, Double quantity)
8 | implements Serializable {
9 | }
10 |
--------------------------------------------------------------------------------
/common/dto/src/main/java/com/ubaid/ms/common/dto/ExceptionDTO.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.common.dto;
2 |
3 | import lombok.Data;
4 | import lombok.NoArgsConstructor;
5 |
6 | import java.util.Date;
7 |
8 | @Data
9 | @NoArgsConstructor
10 | public class ExceptionDTO {
11 | private String message;
12 | private String cause;
13 | private Date timeStamp;
14 | }
15 |
--------------------------------------------------------------------------------
/common/dto/src/main/java/com/ubaid/ms/common/dto/ExchangeRateDTO.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.common.dto;
2 |
3 | import lombok.Data;
4 | import lombok.NoArgsConstructor;
5 |
6 | import java.util.Date;
7 | import java.util.Map;
8 |
9 | @Data
10 | @NoArgsConstructor
11 | public class ExchangeRateDTO {
12 | private Boolean success;
13 | private String date;
14 | private Long timestamp;
15 | private String base;
16 | private Map rates;
17 | }
18 |
--------------------------------------------------------------------------------
/common/dto/src/main/java/com/ubaid/ms/common/dto/ExchangeValueDTO.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.common.dto;
2 |
3 | import lombok.Data;
4 | import lombok.NoArgsConstructor;
5 |
6 |
7 | import java.util.Objects;
8 |
9 | @Data
10 | @NoArgsConstructor
11 | public class ExchangeValueDTO {
12 | private Long id;
13 | private String from;
14 | private Double quantity;
15 | private String to;
16 | private Double exchangeRate;
17 | private Double exchangedCurrencyQuantity;
18 | private Integer port;
19 | private String ipAddress;
20 |
21 | @Override
22 | public boolean equals(Object o) {
23 | if (this == o) return true;
24 | if (o == null || getClass() != o.getClass()) return false;
25 | ExchangeValueDTO that = (ExchangeValueDTO) o;
26 | return from.equals(that.from) &&
27 | to.equals(that.to) &&
28 | exchangeRate.equals(that.exchangeRate);
29 | }
30 |
31 | @Override
32 | public int hashCode() {
33 | return Objects.hash(from, to, exchangeRate);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/common/dto/src/main/java/com/ubaid/ms/common/dto/Rate.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.common.dto;
2 |
3 | import lombok.Data;
4 | import lombok.NoArgsConstructor;
5 |
6 |
7 | @Data
8 | @NoArgsConstructor
9 | public class Rate {
10 | private String code;
11 | private Double value;
12 | }
13 |
--------------------------------------------------------------------------------
/common/dto/src/main/java/com/ubaid/ms/common/dto/ValueDTO.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.common.dto;
2 |
3 | import lombok.Data;
4 | import lombok.NoArgsConstructor;
5 |
6 |
7 | @Data
8 | @NoArgsConstructor
9 | public class ValueDTO {
10 | private Integer port;
11 | private String ipAddress;
12 | private Double value;
13 | }
14 |
--------------------------------------------------------------------------------
/common/dto/src/main/java/com/ubaid/ms/common/dto/auth/LoginCred.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.common.dto.auth;
2 |
3 | import lombok.Data;
4 |
5 | @Data
6 | public class LoginCred {
7 | private String username;
8 | private String password;
9 | }
10 |
--------------------------------------------------------------------------------
/common/dto/src/main/java/com/ubaid/ms/common/dto/serviceinfo/Commit.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.common.dto.serviceinfo;
2 |
3 | import java.time.Instant;
4 |
5 | public record Commit(String id, Instant time) {
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/common/dto/src/main/java/com/ubaid/ms/common/dto/serviceinfo/Git.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.common.dto.serviceinfo;
2 |
3 | public record Git(String branch, Commit commit) {
4 |
5 | }
6 |
--------------------------------------------------------------------------------
/common/dto/src/main/java/com/ubaid/ms/common/dto/serviceinfo/ServiceInformation.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.common.dto.serviceinfo;
2 |
3 | import com.ubaid.ms.common.dto.serviceinfo.Git;
4 | import io.soabase.recordbuilder.core.RecordBuilder;
5 | import java.time.Instant;
6 |
7 | @RecordBuilder
8 | public record ServiceInformation(String name,
9 | Git git) {
10 | }
11 |
--------------------------------------------------------------------------------
/common/exception/.gitignore:
--------------------------------------------------------------------------------
1 | /target
2 | *.iml
3 |
--------------------------------------------------------------------------------
/common/exception/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 4.0.0
5 |
6 |
7 | com.ubaid.ms.common
8 | common
9 | 0.0.3-SNAPSHOT
10 |
11 |
12 | exception
13 | 0.0.3-SNAPSHOT
14 | Exception
15 |
16 |
--------------------------------------------------------------------------------
/common/exception/readme.md:
--------------------------------------------------------------------------------
1 | About
2 | =====
3 | 1. This is a pure Java module which contains the exception classes which are shared across the application.
--------------------------------------------------------------------------------
/common/exception/src/main/java/com/ubaid/ms/common/util/exception/CCException.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.common.util.exception;
2 |
3 | public class CCException extends RuntimeException {
4 | public CCException() {
5 | }
6 |
7 | public CCException(Throwable cause) {
8 | super(cause);
9 | }
10 |
11 | public CCException(String message, Throwable cause) {
12 | super(message, cause);
13 | }
14 |
15 | public CCException(String message) { super(message);}
16 | }
17 |
--------------------------------------------------------------------------------
/common/exception/src/main/java/com/ubaid/ms/common/util/exception/ExchangeValueNotFound.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.common.util.exception;
2 |
3 | public class ExchangeValueNotFound extends CCException{
4 |
5 | public ExchangeValueNotFound(Throwable cause) {
6 | super(cause);
7 | }
8 |
9 | public ExchangeValueNotFound(String message, Throwable cause) {
10 | super(message, cause);
11 | }
12 |
13 | public ExchangeValueNotFound(String message) {
14 | super(message);
15 | }
16 |
17 | public ExchangeValueNotFound() {
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/common/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 4.0.0
5 |
6 | com.ubaid.ms.common
7 | common
8 | 0.0.3-SNAPSHOT
9 | Common Modules
10 | A Parent Pom file for all common modules of Currency Conversion App
11 | pom
12 |
13 |
14 | dto
15 | exception
16 | util
17 |
18 |
19 |
20 | 17
21 | UTF-8
22 |
23 |
24 |
25 |
26 | org.projectlombok
27 | lombok
28 | 1.18.20
29 | provided
30 |
31 |
32 |
33 |
34 |
35 |
36 | org.apache.maven.plugins
37 | maven-compiler-plugin
38 | 3.8.1
39 |
40 | ${java.version}
41 | ${java.version}
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/common/readme.md:
--------------------------------------------------------------------------------
1 | About
2 | =====
3 | 1. This directory contains the different modules which are shared across the services
4 |
5 | Dependencies
6 | ============
7 | - ### Lombok
--------------------------------------------------------------------------------
/common/util/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | /target
--------------------------------------------------------------------------------
/common/util/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | com.ubaid.ms.common
5 | common
6 | 0.0.3-SNAPSHOT
7 |
8 | 4.0.0
9 |
10 | util
11 | 0.0.3-SNAPSHOT
12 | Util
13 |
14 |
--------------------------------------------------------------------------------
/config/.dockerignore:
--------------------------------------------------------------------------------
1 | /target
2 | .gitignore
3 | *.iml
4 | Dockerfile
5 | Dockerfile.multistage
6 | readme.md
--------------------------------------------------------------------------------
/config/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 | !**/src/main/**
5 | !**/src/test/**
6 |
7 | ### STS ###
8 | .apt_generated
9 | .classpath
10 | .factorypath
11 | .project
12 | .settings
13 | .springBeans
14 | .sts4-cache
15 |
16 | ### IntelliJ IDEA ###
17 | .idea
18 | *.iws
19 | *.iml
20 | *.ipr
21 |
22 | ### NetBeans ###
23 | /nbproject/private/
24 | /nbbuild/
25 | /dist/
26 | /nbdist/
27 | /.nb-gradle/
28 | build/
29 |
30 | ### VS Code ###
31 | .vscode/
32 |
--------------------------------------------------------------------------------
/config/Dockerfile.multistage:
--------------------------------------------------------------------------------
1 | ARG APP_VERSION
2 | FROM ubaidurehman/3cn-parent:${APP_VERSION} as build
3 | LABEL maintainer="urehman.bese16seecs@seecs.edu.pk"
4 | VOLUME /tmp
5 | WORKDIR /
6 | ADD . .
7 | RUN mvn clean install -DskipTests
8 |
9 | FROM openjdk:17-slim
10 | VOLUME /tmp
11 | WORKDIR /
12 | EXPOSE 8888
13 | ARG APP_VERSION
14 | COPY --from=build /target/config-${APP_VERSION}.jar service.jar
15 | ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-Dspring.profiles.active=dev","-jar","/service.jar"]
16 |
--------------------------------------------------------------------------------
/config/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 |
5 | com.ubaid.ms
6 | CC-CN-APP
7 | 0.0.3-SNAPSHOT
8 |
9 |
10 |
11 | config
12 | 0.0.3-SNAPSHOT
13 | Config Server
14 | Cloud Configuration Server
15 |
16 |
17 |
18 |
19 | org.springframework.cloud
20 | spring-cloud-config-server
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/config/readme.md:
--------------------------------------------------------------------------------
1 | About
2 | =====
3 | 1. Config Server which automatically injects configurations where we import participant configs to our apps
4 |
5 | Dependencies
6 | ============
7 | - #### Cloud
8 | - ##### Config Server
9 | - spring-cloud-config-server
10 | - #### [Dependencies From Parent](./../moreinfo.md#Dependencies-from-parent)
11 |
12 | Spring Cloud Configuration Server
13 | =================================
14 |
15 | 2. In application.properties add application.name and server.port
16 | 3. Add @EnableConfigServer at main class
17 | 4. Link a local repository as Source
18 | 5. Create a file in a local repository about api-composer.properties
19 | 6. Add ls.max and ls.min in this file
20 | 7. Add spring.cloud.config.server.git.uri=location of
21 | /path/to/git/repo/properties/file
22 | 8. Now we can navigate http://localhost:8888/api-composer/default to
23 | check the properties of api-composer.properties
24 | 9. 10. Now we can create files such as api-composer-dev.properties
25 | and api-composer-qa, and we have options to navigate to
26 | 11. http://localhost:8888/api-composer/dev or
27 | http://localhost:8888/api-composer/qa
28 |
29 |
--------------------------------------------------------------------------------
/config/src/main/resources/application-dev.yml:
--------------------------------------------------------------------------------
1 | spring:
2 | cloud:
3 | config:
4 | server:
5 | git:
6 | uri: https://github.com/UbaidurRehman1/public-repo.git
7 | skip-ssl-validation: true
8 | timeout: 60
--------------------------------------------------------------------------------
/config/src/main/resources/application-local.yml:
--------------------------------------------------------------------------------
1 | spring:
2 | cloud:
3 | config:
4 | server:
5 | git:
6 | uri: file://${user.home}/dev/test/public-repo
7 | skip-ssl-validation: true
--------------------------------------------------------------------------------
/config/src/main/resources/application-prod.yml:
--------------------------------------------------------------------------------
1 | spring:
2 | cloud:
3 | config:
4 | server:
5 | git:
6 | uri: https://github.com/UbaidurRehman1/public-repo.git
7 | skip-ssl-validation: true
8 | timeout: 60
--------------------------------------------------------------------------------
/config/src/main/resources/application.yml:
--------------------------------------------------------------------------------
1 | spring:
2 | application:
3 | name: spring-cloud-config-server
4 | profiles:
5 | active: @activatedProperties@
6 | mvc:
7 | pathmatch:
8 | matching-strategy: ant_path_matcher
9 | main:
10 | allow-bean-definition-overriding: true
11 | server:
12 | port: 8888
--------------------------------------------------------------------------------
/country/.dockerignore:
--------------------------------------------------------------------------------
1 | /target
2 | .gitignore
3 | country.iml
4 | Dockerfile
5 | Dockerfile.multistage
6 | readme.md
--------------------------------------------------------------------------------
/country/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 | !**/src/main/**/target/
5 | !**/src/test/**/target/
6 |
7 | ### STS ###
8 | .apt_generated
9 | .classpath
10 | .factorypath
11 | .project
12 | .settings
13 | .springBeans
14 | .sts4-cache
15 |
16 | ### IntelliJ IDEA ###
17 | .idea
18 | *.iws
19 | *.iml
20 | *.ipr
21 |
22 | ### NetBeans ###
23 | /nbproject/private/
24 | /nbbuild/
25 | /dist/
26 | /nbdist/
27 | /.nb-gradle/
28 | build/
29 | !**/src/main/**/build/
30 | !**/src/test/**/build/
31 |
32 | ### VS Code ###
33 | .vscode/
34 |
--------------------------------------------------------------------------------
/country/Dockerfile.multistage:
--------------------------------------------------------------------------------
1 | ARG APP_VERSION
2 | FROM ubaidurehman/3cn-parent:${APP_VERSION} as build
3 | LABEL maintainer="urehman.bese16seecs@seecs.edu.pk"
4 | VOLUME /tmp
5 | WORKDIR /
6 | ADD . .
7 | RUN mvn clean install -DskipTests
8 |
9 | FROM openjdk:17-slim
10 | VOLUME /tmp
11 | WORKDIR /
12 | EXPOSE 8300
13 | ARG APP_VERSION
14 | COPY --from=build /target/country-${APP_VERSION}.jar service.jar
15 | ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-Dspring.profiles.active=dev","-jar","/service.jar"]
16 |
--------------------------------------------------------------------------------
/country/readme.md:
--------------------------------------------------------------------------------
1 | About
2 | =====
3 | - [Country Service](http://localhost:8755/swagger-ui/index.html?urls.primaryName=country)
4 |
5 | Dependencies
6 | ============
7 | - #### Web (embedded tomcat + MVC)
8 | - spring-boot-starter-web
9 | - #### Data
10 | - spring-boot-starter-data-jpa
11 | - mysql-connector-java
12 | - #### Cloud
13 | - ##### Config Client
14 | - spring-cloud-starter-config
15 | - ##### Naming Server Client
16 | - spring-cloud-starter-netflix-eureka-client
17 | - ##### Distributed Tracing
18 | - spring-cloud-sleuth-zipkin
19 | - spring-cloud-starter-sleuth
20 | - #### Security
21 | - ##### Spring Security
22 | - spring-cloud-starter-security
23 | - ##### [OAuth2 Resource Server](./../moreinfo.md#Resource-server)
24 | - spring-boot-starter-oauth2-resource-server
25 | - #### AOP
26 | - spring-boot-starter-aop
27 | - #### Logstash (Sending logs to Logstash)
28 | - logstash-logging-spring-boot-starter
29 | - ### Database Migration (Liquibase)
30 | - liquibase-core
31 | - jackson-module-jaxb-annotations
32 | - #### [Dependencies From Parent](./../moreinfo.md#Dependencies-from-parent)
33 |
34 | [Distributed Tracing](./../moreinfo.md#distributed-tracing)
35 | -----------------------------------------------------------
36 | [ELK Stack](./../moreinfo.md#elk-stack)
37 | ---------------------------------------
38 | [Audience Validation](./../moreinfo.md#audience-validation)
39 | ------------------------
--------------------------------------------------------------------------------
/country/src/main/java/com/ubaid/ms/CountryApplication.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms;
2 |
3 | import brave.sampler.Sampler;
4 | import org.springframework.boot.SpringApplication;
5 | import org.springframework.boot.autoconfigure.SpringBootApplication;
6 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
7 | import org.springframework.context.annotation.Bean;
8 |
9 | @SpringBootApplication
10 | @EnableDiscoveryClient
11 | public class CountryApplication {
12 |
13 | public static void main(String[] args) {
14 | SpringApplication.run(CountryApplication.class, args);
15 | }
16 |
17 | @Bean
18 | public Sampler defaultSampler() {
19 | return Sampler.ALWAYS_SAMPLE;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/country/src/main/java/com/ubaid/ms/country/advice/ExceptionController.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.country.advice;
2 |
3 | import com.ubaid.ms.common.dto.ExceptionDTO;
4 | import com.ubaid.ms.common.util.exception.CCException;
5 | import org.springframework.http.HttpStatus;
6 | import org.springframework.http.ResponseEntity;
7 | import org.springframework.web.bind.annotation.ControllerAdvice;
8 | import org.springframework.web.bind.annotation.ExceptionHandler;
9 |
10 | import java.util.Date;
11 |
12 | @ControllerAdvice
13 | public class ExceptionController {
14 |
15 | @ExceptionHandler(CCException.class)
16 | public ResponseEntity handleUnknownException(CCException exp) {
17 | ExceptionDTO exceptionDTO = new ExceptionDTO();
18 | exceptionDTO.setMessage(exp.getMessage());
19 | exceptionDTO.setCause(exp.getCause().toString());
20 | exceptionDTO.setTimeStamp(new Date());
21 | return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(exceptionDTO);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/country/src/main/java/com/ubaid/ms/country/aop/TargetMethods.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.country.aop;
2 |
3 | import org.aspectj.lang.annotation.Pointcut;
4 |
5 | public abstract class TargetMethods {
6 |
7 | @Pointcut("execution(* com.ubaid.ms.country.service.CountryCodeService.getAll())")
8 | public void getAll() {
9 | }
10 | }
--------------------------------------------------------------------------------
/country/src/main/java/com/ubaid/ms/country/config/Beans.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.country.config;
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper;
4 | import org.springframework.beans.factory.config.ConfigurableBeanFactory;
5 | import org.springframework.context.annotation.Bean;
6 | import org.springframework.context.annotation.Scope;
7 |
8 | public class Beans {
9 |
10 | @Bean
11 | @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
12 | public ObjectMapper objectMapper() {
13 | return new ObjectMapper();
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/country/src/main/java/com/ubaid/ms/country/config/validator/AudienceValidator.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.country.config.validator;
2 |
3 | import lombok.extern.slf4j.Slf4j;
4 | import org.springframework.security.oauth2.core.OAuth2Error;
5 | import org.springframework.security.oauth2.core.OAuth2TokenValidator;
6 | import org.springframework.security.oauth2.core.OAuth2TokenValidatorResult;
7 | import org.springframework.security.oauth2.jwt.Jwt;
8 |
9 | import static com.ubaid.ms.common.util.Constants.*;
10 |
11 | /**
12 | * This class is responsible to validate {@link AudienceValidator#AUD} in JWT token in the incoming request
13 | * @author ubaid
14 | */
15 | @Slf4j
16 | public class AudienceValidator implements OAuth2TokenValidator {
17 |
18 | private final OAuth2Error error = new OAuth2Error(INVALID_TOKEN, String.format("The required audience %s is missing", AUD), null);
19 | private final static String AUD = COUNTRY_SERVICE;
20 |
21 | @Override
22 | public OAuth2TokenValidatorResult validate(Jwt jwt) {
23 | if (jwt.getAudience().contains(AUD)) {
24 | return OAuth2TokenValidatorResult.success();
25 | } else {
26 | log.error("The required audience {} is missing from the token", AUD);
27 | return OAuth2TokenValidatorResult.failure(error);
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/country/src/main/java/com/ubaid/ms/country/controller/CountryController.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.country.controller;
2 |
3 | import com.ubaid.ms.common.dto.CountryCodeDTO;
4 | import com.ubaid.ms.country.service.CountryCodeService;
5 | import io.swagger.annotations.*;
6 | import lombok.RequiredArgsConstructor;
7 |
8 | import org.springframework.security.access.prepost.PreAuthorize;
9 | import org.springframework.web.bind.annotation.GetMapping;
10 | import org.springframework.web.bind.annotation.RequestMapping;
11 | import org.springframework.web.bind.annotation.RestController;
12 | import java.util.List;
13 |
14 | import static com.ubaid.ms.common.util.Constants.*;
15 | import static com.ubaid.ms.country.config.SwaggerConfig.COUNTRY;
16 |
17 | @Api(tags = COUNTRY)
18 | @RestController
19 | @RequestMapping("v1")
20 | @RequiredArgsConstructor
21 | public class CountryController {
22 |
23 | private final CountryCodeService countryCodeService;
24 |
25 | @ApiOperation(
26 | value = "To get all countries along with currency codes",
27 | authorizations = @Authorization(value = BEARER),
28 | response = CountryCodeDTO.class,
29 | responseContainer = "List"
30 | )
31 | @ApiResponses({
32 | @ApiResponse(code = HTTP_OK, message = "All Countries with currency code fetched successfully"),
33 | @ApiResponse(code = HTTP_UNAUTHORIZED, message = "You are not authorized to send a request")
34 | })
35 | @PreAuthorize("hasAuthority('SCOPE_countries')")
36 | @GetMapping(value = "code", produces = APPLICATION_JSON)
37 | public List getAllCountries() {
38 | return countryCodeService.getAll();
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/country/src/main/java/com/ubaid/ms/country/controller/InfoController.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.country.controller;
2 |
3 | import com.ubaid.ms.common.dto.serviceinfo.ServiceInformation;
4 | import com.ubaid.ms.country.service.InfoService;
5 | import lombok.RequiredArgsConstructor;
6 | import org.springframework.http.ResponseEntity;
7 | import org.springframework.web.bind.annotation.GetMapping;
8 | import org.springframework.web.bind.annotation.RequestMapping;
9 | import org.springframework.web.bind.annotation.RestController;
10 |
11 | @RestController
12 | @RequestMapping("v1")
13 | @RequiredArgsConstructor
14 | public class InfoController {
15 | private final InfoService infoService;
16 |
17 | @GetMapping("info")
18 | public ResponseEntity getInfo() {
19 | return ResponseEntity.ok(infoService.get());
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/country/src/main/java/com/ubaid/ms/country/dao/CountryCodeDAO.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.country.dao;
2 |
3 | import com.ubaid.ms.country.entity.CountryCode;
4 | import org.springframework.data.jpa.repository.JpaRepository;
5 |
6 | public interface CountryCodeDAO extends JpaRepository {
7 |
8 | }
9 |
--------------------------------------------------------------------------------
/country/src/main/java/com/ubaid/ms/country/entity/CountryCode.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.country.entity;
2 |
3 | import lombok.Data;
4 | import lombok.NoArgsConstructor;
5 |
6 | import javax.persistence.*;
7 |
8 | @Entity
9 | @Table
10 | @Data
11 | @NoArgsConstructor
12 | public class CountryCode {
13 |
14 | @Id
15 | @GeneratedValue(strategy = GenerationType.IDENTITY)
16 | private Long id;
17 |
18 | private String country;
19 |
20 | private String currencyName;
21 |
22 | private String currencyCode;
23 |
24 | private Integer number;
25 |
26 | private String isoCode;
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/country/src/main/java/com/ubaid/ms/country/service/CountryCodeService.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.country.service;
2 |
3 |
4 | import com.ubaid.ms.common.dto.CountryCodeDTO;
5 |
6 | import java.util.List;
7 |
8 | public interface CountryCodeService {
9 | List getAll();
10 | }
11 |
--------------------------------------------------------------------------------
/country/src/main/java/com/ubaid/ms/country/service/CountryCodeServiceImp.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.country.service;
2 |
3 | import com.ubaid.ms.common.dto.CountryCodeDTO;
4 | import com.ubaid.ms.country.dao.CountryCodeDAO;
5 | import com.ubaid.ms.country.entity.CountryCode;
6 | import lombok.Getter;
7 | import lombok.RequiredArgsConstructor;
8 | import org.springframework.stereotype.Service;
9 |
10 | import java.util.List;
11 | import java.util.stream.Collectors;
12 |
13 | @Service
14 | @RequiredArgsConstructor
15 | public class CountryCodeServiceImp implements CountryCodeService {
16 |
17 | private final CountryCodeDAO countryCodeDAO;
18 |
19 | @Override
20 | public List getAll() {
21 | return countryCodeDAO
22 | .findAll()
23 | .stream()
24 | .map(countryCode -> new ConvertCountryCodeTODTO(countryCode)
25 | .getCountryCodeDTO())
26 | .collect(Collectors.toList());
27 | }
28 |
29 | @Getter
30 | private static class ConvertCountryCodeTODTO {
31 |
32 | CountryCodeDTO countryCodeDTO;
33 |
34 | ConvertCountryCodeTODTO(CountryCode countryCode) {
35 | convert(countryCode);
36 | }
37 |
38 | private void convert(CountryCode countryCode) {
39 | countryCodeDTO = new CountryCodeDTO();
40 | countryCodeDTO.setCountry(countryCode.getCountry());
41 | countryCodeDTO.setCurrencyCode(countryCode.getCurrencyCode());
42 | countryCodeDTO.setCurrencyName(countryCode.getCurrencyName());
43 | countryCodeDTO.setId(countryCode.getId());
44 | countryCodeDTO.setNumber(countryCode.getNumber());
45 | countryCodeDTO.setIsoCode(countryCode.getIsoCode());
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/country/src/main/java/com/ubaid/ms/country/service/InfoService.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.country.service;
2 |
3 | import com.ubaid.ms.common.dto.serviceinfo.ServiceInformation;
4 |
5 | public interface InfoService {
6 | ServiceInformation get();
7 | }
8 |
--------------------------------------------------------------------------------
/country/src/main/java/com/ubaid/ms/country/service/InfoServiceImpl.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.country.service;
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper;
4 | import com.netflix.appinfo.ApplicationInfoManager;
5 | import com.ubaid.ms.common.dto.serviceinfo.ServiceInformation;
6 | import com.ubaid.ms.common.dto.serviceinfo.ServiceInformationBuilder;
7 | import lombok.RequiredArgsConstructor;
8 | import lombok.extern.slf4j.Slf4j;
9 | import org.springframework.boot.actuate.info.InfoEndpoint;
10 | import org.springframework.stereotype.Service;
11 |
12 | @Service
13 | @Slf4j
14 | @RequiredArgsConstructor
15 | public class InfoServiceImpl implements InfoService {
16 |
17 | private final InfoEndpoint infoEndpoint;
18 | private final ObjectMapper objectMapper;
19 | private final ApplicationInfoManager applicationInfoManager;
20 |
21 | @Override
22 | public ServiceInformation get() {
23 | ServiceInformationBuilder builder = ServiceInformationBuilder
24 | .builder(objectMapper.convertValue(infoEndpoint.info(), ServiceInformation.class));
25 | builder.name(applicationInfoManager.getInfo().getAppName());
26 | ServiceInformation serviceInformation = builder.build();
27 | log.debug("Service Information: {}", serviceInformation);
28 | return serviceInformation;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/country/src/main/resources/application-dev.properties:
--------------------------------------------------------------------------------
1 | #------------------------Config Client--------------------------#
2 | spring.config.import=optional:configserver:http://config:8888
3 | spring.cloud.config.profile=dev
4 | spring.cloud.config.fail-fast=true
5 | spring.cloud.config.request-connect-timeout=30000
6 | spring.cloud.config.request-read-timeout=360000
--------------------------------------------------------------------------------
/country/src/main/resources/application-local.properties:
--------------------------------------------------------------------------------
1 | #------------------------Config Client--------------------------#
2 | spring.config.import=optional:configserver:http://localhost:8888
3 | spring.cloud.config.profile=local
4 |
5 | #------------------------Live Reload --------------------------#
6 | spring.devtools.livereload.port=35732
7 |
8 |
9 | #------------------------Logs --------------------------#
10 | logging.level.org.springframework.cloud.gateway=DEBUG
11 | logging.level.org.springframework.security=DEBUG
12 | logging.level.org.springframework.web.reactive.function.client=DEBUG
13 |
14 |
15 | #------------------------Actuator --------------------------#
16 | management.endpoints.web.exposure.include=health,info
17 | management.endpoint.health.enabled=true
18 | management.endpoint.health.probes.enabled=true
--------------------------------------------------------------------------------
/country/src/main/resources/application-prod.properties:
--------------------------------------------------------------------------------
1 | #------------------------Config Client--------------------------#
2 | spring.config.import=optional:configserver:http://config:8888
3 | spring.cloud.config.profile=prod
4 | spring.cloud.config.fail-fast=true
5 | spring.cloud.config.request-connect-timeout=30000
6 | spring.cloud.config.request-read-timeout=360000
--------------------------------------------------------------------------------
/country/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 | #----------------------------SApplication config-----------------------------------#
2 | spring.application.name=country
3 | server.port=8300
4 |
5 | #----------------------------Active Profile----------------------------------------#
6 | spring.profiles.active=@activatedProperties@
7 |
8 | #----------------------------Static IP---------------------------------------------#
9 | eureka.instance.prefer-ip-address=true
10 | eureka.instance.instance-id=${spring.cloud.client.ip-address}:${server.port}
11 | eureka.instance.hostname=${spring.cloud.client.ip-address}
12 |
13 | #----------------------------Disabling Warnings ---------------------------- ------#
14 | spring.jpa.open-in-view=false
15 |
16 | spring.mvc.pathmatch.matching-strategy=ant_path_matcher
17 | spring.main.allow-circular-references=true
--------------------------------------------------------------------------------
/country/src/main/resources/config.properties:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubaid4j/Cloud-Native-App-Spring-Boot/d023b0a732b43f4196176cd9fa3a67490a79eaab/country/src/main/resources/config.properties
--------------------------------------------------------------------------------
/country/src/main/resources/db/changelog/changes/v0001.sql:
--------------------------------------------------------------------------------
1 | -- liquibase formatted sql
2 | -- changeset ubaid:18Oct2020_2144
3 |
4 | create table country_code (
5 | id bigint primary key auto_increment,
6 | country varchar(255),
7 | country_code varchar(255),
8 | currency_name varchar(255),
9 | number int
10 | );
11 |
--------------------------------------------------------------------------------
/country/src/main/resources/db/changelog/changes/v0002.sql:
--------------------------------------------------------------------------------
1 | -- liquibase formatted sql
2 | -- changeset ubaid:18Oct2020_2005
3 | -- comment changing name of column
4 | alter table country_code
5 | rename column country_code to currency_code;
6 |
--------------------------------------------------------------------------------
/country/src/main/resources/db/changelog/changes/v0004-add_column_in_country_code_table.sql:
--------------------------------------------------------------------------------
1 | -- liquibase formatted sql
2 | -- changeset ubaid:12Nov2020_1847
3 | -- comment add column iso code in country code table
4 | alter table country_code
5 | add iso_code int;
--------------------------------------------------------------------------------
/country/src/main/resources/db/changelog/changes/v0005-updating_iso_column_to_integer.sql:
--------------------------------------------------------------------------------
1 | -- liquibase formatted sql
2 | -- changeset ubaid:12Nov2020_1958
3 | -- comment add column iso code in country code table
4 | alter table country_code
5 | modify iso_code varchar(2);
--------------------------------------------------------------------------------
/country/src/main/resources/db/changelog/changes/v0005a-correcting_iso_column_to10_varchar.sql:
--------------------------------------------------------------------------------
1 | -- liquibase formatted sql
2 | -- changeset ubaid:12Nov2020_2001
3 | -- comment add column iso code in country code table
4 | alter table country_code
5 | modify iso_code varchar(10);
--------------------------------------------------------------------------------
/country/src/main/resources/db/changelog/db.changelog-master.yaml:
--------------------------------------------------------------------------------
1 | databaseChangeLog:
2 | - includeAll:
3 | path: db/changelog/changes
--------------------------------------------------------------------------------
/country/src/test/java/com/ubaid/ms/counteryservice/CountryApplicationTests.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.counteryservice;
2 |
3 | import org.junit.jupiter.api.Test;
4 | import org.springframework.boot.test.context.SpringBootTest;
5 |
6 | @SpringBootTest
7 | class CountryApplicationTests {
8 |
9 | @Test
10 | void contextLoads() {
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/country/src/test/resources/application.properties:
--------------------------------------------------------------------------------
1 | #----------------------------SApplication config-----------------------------------#
2 | spring.application.name=country
3 | server.port=8300
4 |
5 | #----------------------------Active Profile----------------------------------------#
6 | spring.profiles.active=test
7 |
8 | #------------------------Config Client---------------------------------------------#
9 | spring.config.import=optional:configserver:http://localhost:8888
10 |
11 | #----------------------------Static IP---------------------------------------------#
12 | eureka.instance.prefer-ip-address=true
13 | eureka.instance.instance-id=${spring.cloud.client.ip-address}:${server.port}
14 | eureka.instance.hostname=${spring.cloud.client.ip-address}
15 |
16 | #----------------------------Disabling Spring Ribbon Client (In maintenance) ------#
17 | spring.cloud.loadbalancer.ribbon.enabled=false
18 | #----------------------------Disabling Warnings -----------------------------------#
19 | spring.jpa.open-in-view=false
--------------------------------------------------------------------------------
/currency-conversion/.dockerignore:
--------------------------------------------------------------------------------
1 | /target
2 | .gitignore
3 | *.iml
4 | Dockerfile
5 | Dockerfile.multistage
6 | readme.md
7 | runAllTests.sh
--------------------------------------------------------------------------------
/currency-conversion/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 | !**/src/main/**
5 | !**/src/test/**
6 |
7 | ### STS ###
8 | .apt_generated
9 | .classpath
10 | .factorypath
11 | .project
12 | .settings
13 | .springBeans
14 | .sts4-cache
15 |
16 | ### IntelliJ IDEA ###
17 | .idea
18 | *.iws
19 | *.iml
20 | *.ipr
21 |
22 | ### NetBeans ###
23 | /nbproject/private/
24 | /nbbuild/
25 | /dist/
26 | /nbdist/
27 | /.nb-gradle/
28 | build/
29 |
30 | ### VS Code ###
31 | .vscode/
32 |
--------------------------------------------------------------------------------
/currency-conversion/Dockerfile.multistage:
--------------------------------------------------------------------------------
1 | ARG APP_VERSION
2 | FROM ubaidurehman/3cn-parent:${APP_VERSION} as build
3 | LABEL maintainer="urehman.bese16seecs@seecs.edu.pk"
4 | VOLUME /tmp
5 | WORKDIR /
6 | ADD . .
7 | RUN mvn clean install -DskipTests
8 |
9 | FROM openjdk:17-slim
10 | VOLUME /tmp
11 | WORKDIR /
12 | EXPOSE 5200
13 | ARG APP_VERSION
14 | COPY --from=build /target/currency-conversion-${APP_VERSION}.jar service.jar
15 | ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-Dspring.profiles.active=dev","-jar","/service.jar"]
16 |
--------------------------------------------------------------------------------
/currency-conversion/runAllTests.sh:
--------------------------------------------------------------------------------
1 | mvn clean test
--------------------------------------------------------------------------------
/currency-conversion/src/main/java/com/ubaid/ms/CurrencyConversionApp.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
6 | import org.springframework.cloud.openfeign.EnableFeignClients;
7 | import org.springframework.context.annotation.EnableAspectJAutoProxy;
8 |
9 | import static com.ubaid.ms.common.util.Constants.APP_ROOT_PACKAGE;
10 |
11 | @SpringBootApplication
12 | @EnableFeignClients(basePackages = {APP_ROOT_PACKAGE})
13 | @EnableDiscoveryClient
14 | @EnableAspectJAutoProxy
15 | public class CurrencyConversionApp {
16 | public static void main(String[] args) {
17 | SpringApplication.run(CurrencyConversionApp.class, args);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/currency-conversion/src/main/java/com/ubaid/ms/currencyconversion/aop/TargetMethods.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.currencyconversion.aop;
2 |
3 | import org.aspectj.lang.annotation.Pointcut;
4 |
5 | public abstract class TargetMethods {
6 |
7 | @Pointcut("execution(* com.ubaid.ms.currencyconversion.service.CurrencyConversionService.convertCurrency(com.ubaid.ms.common.dto.CurrencyInfoDTO))")
8 | public void convertCurrency() {}
9 | }
--------------------------------------------------------------------------------
/currency-conversion/src/main/java/com/ubaid/ms/currencyconversion/config/Beans.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.currencyconversion.config;
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper;
4 | import org.springframework.beans.factory.config.ConfigurableBeanFactory;
5 | import org.springframework.context.annotation.Bean;
6 | import org.springframework.context.annotation.Scope;
7 |
8 | public class Beans {
9 |
10 | @Bean
11 | @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
12 | public ObjectMapper objectMapper() {
13 | return new ObjectMapper();
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/currency-conversion/src/main/java/com/ubaid/ms/currencyconversion/config/Config.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.currencyconversion.config;
2 |
3 | import lombok.Data;
4 | import lombok.NoArgsConstructor;
5 | import org.springframework.boot.context.properties.ConfigurationProperties;
6 | import org.springframework.stereotype.Component;
7 |
8 | /**
9 | * and define the prefix
10 | * same as in the application.properties file
11 | *
12 | * @author UbaidurRehman
13 | */
14 |
15 | @ConfigurationProperties(prefix = "ls")
16 | @Component
17 | @Data
18 | @NoArgsConstructor
19 | public class Config {
20 | private int min;
21 | private int max;
22 | }
23 |
--------------------------------------------------------------------------------
/currency-conversion/src/main/java/com/ubaid/ms/currencyconversion/config/MessageBrokerConfig.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.currencyconversion.config;
2 |
3 | import org.springframework.amqp.core.Queue;
4 | import org.springframework.context.annotation.Bean;
5 | import org.springframework.context.annotation.Configuration;
6 | import static com.ubaid.ms.common.util.Constants.AUDIT_QUEUE;
7 |
8 | @Configuration
9 | public class MessageBrokerConfig {
10 |
11 | @Bean
12 | public Queue auditQueue() {
13 | return new Queue(AUDIT_QUEUE, false);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/currency-conversion/src/main/java/com/ubaid/ms/currencyconversion/controller/InfoController.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.currencyconversion.controller;
2 |
3 | import com.ubaid.ms.common.dto.serviceinfo.ServiceInformation;
4 | import com.ubaid.ms.currencyconversion.service.InfoService;
5 | import lombok.RequiredArgsConstructor;
6 | import org.springframework.http.ResponseEntity;
7 | import org.springframework.web.bind.annotation.GetMapping;
8 | import org.springframework.web.bind.annotation.RequestMapping;
9 | import org.springframework.web.bind.annotation.RestController;
10 |
11 | @RestController
12 | @RequestMapping("v1")
13 | @RequiredArgsConstructor
14 | public class InfoController {
15 | private final InfoService infoService;
16 |
17 | @GetMapping("info")
18 | public ResponseEntity getInfo() {
19 | return ResponseEntity.ok(infoService.get());
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/currency-conversion/src/main/java/com/ubaid/ms/currencyconversion/entity/Limit.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.currencyconversion.entity;
2 |
3 | import lombok.Data;
4 | import lombok.NoArgsConstructor;
5 |
6 | @Data
7 | @NoArgsConstructor
8 | public class Limit {
9 | private int max;
10 | private int min;
11 | private int port;
12 | }
13 |
--------------------------------------------------------------------------------
/currency-conversion/src/main/java/com/ubaid/ms/currencyconversion/exceptionController/ExceptionController.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.currencyconversion.exceptionController;
2 |
3 | import com.ubaid.ms.common.dto.ExceptionDTO;
4 |
5 | import com.ubaid.ms.common.util.exception.CCException;
6 | import org.springframework.http.HttpStatus;
7 | import org.springframework.http.ResponseEntity;
8 | import org.springframework.web.bind.annotation.ExceptionHandler;
9 | import org.springframework.web.bind.annotation.RestControllerAdvice;
10 |
11 | import java.util.Date;
12 |
13 | @RestControllerAdvice
14 | public class ExceptionController {
15 |
16 | @ExceptionHandler(CCException.class)
17 | public ResponseEntity handleUnknownException(CCException exp) {
18 | ExceptionDTO exceptionDTO = new ExceptionDTO();
19 | exceptionDTO.setMessage(exp.getMessage());
20 | exceptionDTO.setCause(exp.getCause().toString());
21 | exceptionDTO.setTimeStamp(new Date());
22 | return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(exceptionDTO);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/currency-conversion/src/main/java/com/ubaid/ms/currencyconversion/feignProxy/CurrencyConversionServiceProxy.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.currencyconversion.feignProxy;
2 |
3 | import static com.ubaid.ms.common.util.Constants.API_GATEWAY;
4 | import static com.ubaid.ms.common.util.Constants.AUTHORIZATION;
5 |
6 | import com.ubaid.ms.common.dto.ValueDTO;
7 | import org.springframework.cloud.openfeign.FeignClient;
8 | import org.springframework.web.bind.annotation.GetMapping;
9 | import org.springframework.web.bind.annotation.PathVariable;
10 | import org.springframework.web.bind.annotation.RequestHeader;
11 |
12 | @FeignClient(name = API_GATEWAY)
13 | public interface CurrencyConversionServiceProxy {
14 |
15 | @GetMapping("math/v1/multiply/{currency}/{conversion-rate}")
16 | ValueDTO convert(
17 | @RequestHeader(value = AUTHORIZATION) String token,
18 | @PathVariable("currency") Double currency,
19 | @PathVariable("conversion-rate") Double rate);
20 | }
21 |
--------------------------------------------------------------------------------
/currency-conversion/src/main/java/com/ubaid/ms/currencyconversion/feignProxy/CurrencyExchangeServiceProxy.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.currencyconversion.feignProxy;
2 |
3 | import static com.ubaid.ms.common.util.Constants.*;
4 |
5 | import com.ubaid.ms.common.dto.ExchangeValueDTO;
6 | import org.springframework.cloud.openfeign.FeignClient;
7 | import org.springframework.web.bind.annotation.GetMapping;
8 | import org.springframework.web.bind.annotation.PathVariable;
9 | import org.springframework.web.bind.annotation.RequestHeader;
10 |
11 | @FeignClient(name = API_GATEWAY)
12 | public interface CurrencyExchangeServiceProxy {
13 |
14 | @GetMapping("currency-exchange/v1/from/{from}/to/{to}")
15 | ExchangeValueDTO getCurrencyExchangeRate(
16 | @RequestHeader(value = AUTHORIZATION) String token,
17 | @PathVariable(value = "from") String from,
18 | @PathVariable(value = "to") String to);
19 | }
--------------------------------------------------------------------------------
/currency-conversion/src/main/java/com/ubaid/ms/currencyconversion/service/AuditService.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.currencyconversion.service;
2 |
3 | import com.ubaid.ms.common.dto.AuditDTO;
4 |
5 | public interface AuditService {
6 | void sendAuditLogToMQ(AuditDTO auditDTO);
7 | }
8 |
--------------------------------------------------------------------------------
/currency-conversion/src/main/java/com/ubaid/ms/currencyconversion/service/AuditServiceImpl.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.currencyconversion.service;
2 |
3 | import com.ubaid.ms.common.dto.AuditDTO;
4 | import lombok.RequiredArgsConstructor;
5 | import lombok.extern.slf4j.Slf4j;
6 | import org.springframework.amqp.core.Queue;
7 | import org.springframework.amqp.rabbit.core.RabbitTemplate;
8 | import org.springframework.stereotype.Service;
9 |
10 | @Service
11 | @RequiredArgsConstructor
12 | @Slf4j
13 | public class AuditServiceImpl implements AuditService {
14 |
15 | private final RabbitTemplate rabbitTemplate;
16 | private final Queue queue;
17 |
18 | @Override
19 | public void sendAuditLogToMQ(AuditDTO auditDTO) {
20 | log.debug("Sending Audit Log [{}] to message broker", auditDTO);
21 | rabbitTemplate.convertAndSend(queue.getName(), auditDTO);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/currency-conversion/src/main/java/com/ubaid/ms/currencyconversion/service/AuthService.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.currencyconversion.service;
2 |
3 | import org.springframework.security.core.Authentication;
4 |
5 | public interface AuthService {
6 | Authentication getAuthentication();
7 | String getAccessToken();
8 | String getBearerToken();
9 | String getUserUUID();
10 | }
11 |
--------------------------------------------------------------------------------
/currency-conversion/src/main/java/com/ubaid/ms/currencyconversion/service/CurrencyConversionService.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.currencyconversion.service;
2 |
3 |
4 | import com.ubaid.ms.common.dto.CurrencyInfoDTO;
5 | import com.ubaid.ms.common.dto.ExchangeValueDTO;
6 |
7 | public interface CurrencyConversionService {
8 | ExchangeValueDTO convertCurrency(CurrencyInfoDTO currencyInfo);
9 | }
10 |
--------------------------------------------------------------------------------
/currency-conversion/src/main/java/com/ubaid/ms/currencyconversion/service/InfoService.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.currencyconversion.service;
2 |
3 | import com.ubaid.ms.common.dto.serviceinfo.ServiceInformation;
4 |
5 | public interface InfoService {
6 | ServiceInformation get();
7 | }
8 |
--------------------------------------------------------------------------------
/currency-conversion/src/main/java/com/ubaid/ms/currencyconversion/service/InfoServiceImpl.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.currencyconversion.service;
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper;
4 | import com.netflix.appinfo.ApplicationInfoManager;
5 | import com.ubaid.ms.common.dto.serviceinfo.ServiceInformation;
6 | import com.ubaid.ms.common.dto.serviceinfo.ServiceInformationBuilder;
7 | import lombok.RequiredArgsConstructor;
8 | import lombok.extern.slf4j.Slf4j;
9 | import org.springframework.boot.actuate.info.InfoEndpoint;
10 | import org.springframework.stereotype.Service;
11 |
12 | @Service
13 | @Slf4j
14 | @RequiredArgsConstructor
15 | public class InfoServiceImpl implements InfoService {
16 |
17 | private final InfoEndpoint infoEndpoint;
18 | private final ObjectMapper objectMapper;
19 | private final ApplicationInfoManager applicationInfoManager;
20 |
21 | @Override
22 | public ServiceInformation get() {
23 | ServiceInformationBuilder builder = ServiceInformationBuilder
24 | .builder(objectMapper.convertValue(infoEndpoint.info(), ServiceInformation.class));
25 | builder.name(applicationInfoManager.getInfo().getAppName());
26 | ServiceInformation serviceInformation = builder.build();
27 | log.debug("Service Information: {}", serviceInformation);
28 | return serviceInformation;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/currency-conversion/src/main/java/com/ubaid/ms/currencyconversion/service/RequestService.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.currencyconversion.service;
2 |
3 | public interface RequestService {
4 | String getClientIP();
5 | }
6 |
--------------------------------------------------------------------------------
/currency-conversion/src/main/java/com/ubaid/ms/currencyconversion/util/BearerToken.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.currencyconversion.util;
2 |
3 | import lombok.Data;
4 |
5 | import static com.ubaid.ms.common.util.Constants.*;
6 |
7 | @Data
8 | public class BearerToken {
9 |
10 | private final String bearerToken;
11 |
12 | public BearerToken(String accessToken) {
13 | this.bearerToken = BEARER + SINGLE_SPACE + accessToken;
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/currency-conversion/src/main/resources/application-dev.properties:
--------------------------------------------------------------------------------
1 | #------------------------Config Client--------------------------#
2 | spring.config.import=optional:configserver:http://config:8888
3 | spring.cloud.config.profile=dev
4 | spring.cloud.config.fail-fast=true
5 | spring.cloud.config.request-connect-timeout=30000
6 | spring.cloud.config.request-read-timeout=360000
7 |
8 |
--------------------------------------------------------------------------------
/currency-conversion/src/main/resources/application-local.properties:
--------------------------------------------------------------------------------
1 | #------------------------Config Client --------------------------#
2 | spring.config.import=optional:configserver:http://localhost:8888
3 | spring.cloud.config.profile=local
4 |
5 | #------------------------Live Reload --------------------------#
6 | spring.devtools.livereload.port=35733
7 |
8 | #------------------------Logs --------------------------#
9 | logging.level.org.springframework.security=DEBUG
10 | logging.level.root=WARN
11 | logging.level.web=WARN
12 | logging.level.com.ubaid.ms=TRACE
13 |
14 | spring.devtools.livereload.enabled=true
15 |
16 | #------------------------Actuator --------------------------#
17 | management.endpoints.web.exposure.include=health,info
18 | management.endpoint.health.enabled=true
19 | management.endpoint.health.probes.enabled=true
--------------------------------------------------------------------------------
/currency-conversion/src/main/resources/application-prod.properties:
--------------------------------------------------------------------------------
1 | #------------------------Config Client--------------------------#
2 | spring.config.import=optional:configserver:http://config:8888
3 | spring.cloud.config.profile=prod
4 | spring.cloud.config.fail-fast=true
5 | spring.cloud.config.request-connect-timeout=30000
6 | spring.cloud.config.request-read-timeout=360000
--------------------------------------------------------------------------------
/currency-conversion/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 | #---------------------------------Application config---------------------------------#
2 | spring.application.name=currency-conversion
3 | server.port=5200
4 |
5 | #---------------------------------URL of Config Server-------------------------------#
6 | spring.cloud.config.uri=http://config-server:8888
7 |
8 | #---------------------------------Overriding Bean------------------------------------#
9 | spring.main.allow-bean-definition-overriding=true
10 |
11 | #---------------------------------Numeric IPs----------------------------------------#
12 | eureka.instance.prefer-ip-address=true
13 | eureka.instance.instance-id=${spring.cloud.client.ip-address}:${server.port}
14 | eureka.instance.hostname=${spring.cloud.client.ip-address}
15 |
16 | #---------------------------------Profile of Config Server---------------------------#
17 | spring.profiles.active=@activatedProperties@
18 |
19 | #--------------Disable Security to refresh the bus (to fetch updated config)---------#
20 | management.endpoints.web.exposure.include=*
21 |
22 | spring.mvc.pathmatch.matching-strategy=ant_path_matcher
23 | spring.main.allow-circular-references=true
--------------------------------------------------------------------------------
/currency-conversion/src/main/resources/config.properties:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubaid4j/Cloud-Native-App-Spring-Boot/d023b0a732b43f4196176cd9fa3a67490a79eaab/currency-conversion/src/main/resources/config.properties
--------------------------------------------------------------------------------
/currency-conversion/src/test/resources/application.properties:
--------------------------------------------------------------------------------
1 | #---------------------------------Application config---------------------------------#
2 | spring.application.name=currency-conversion
3 | server.port=5200
4 |
5 | #---------------------------------Profile of Config Server---------------------------#
6 | spring.profiles.active=test
7 |
8 | #---------------------------------URL of Config Server-------------------------------#
9 | spring.config.import=optional:configserver:http://localhost:8888
10 | spring.cloud.config.profile=test
11 |
12 | #------------------------issuer uri --------------------------#
13 | spring.security.oauth2.resourceserver.jwt.issuer-uri=http://localhost:9999/auth/realms/3cn
14 | spring.security.oauth2.resourceserver.jwt.jwk-set-uri=http://localhost:9999/auth/realms/3cn/protocol/openid-connect/certs
15 | spring.main.allow-bean-definition-overriding=true
16 |
17 | #---------------------------------Numeric IPs----------------------------------------#
18 | eureka.instance.prefer-ip-address=true
19 | eureka.instance.instance-id=${spring.cloud.client.ip-address}:${server.port}
20 | eureka.instance.hostname=${spring.cloud.client.ip-address}
21 |
22 | #--------------Disable Security to refresh the bus (to fetch updated config)---------#
23 | management.endpoints.web.exposure.include=*
24 |
25 | #---------------------------------Disable deprecated ribbon client------------------#
26 | spring.devtools.add-properties=false
27 |
--------------------------------------------------------------------------------
/currency-conversion/src/test/resources/config.properties:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubaid4j/Cloud-Native-App-Spring-Boot/d023b0a732b43f4196176cd9fa3a67490a79eaab/currency-conversion/src/test/resources/config.properties
--------------------------------------------------------------------------------
/currency-exchange/.dockerignore:
--------------------------------------------------------------------------------
1 | /target
2 | .gitignore
3 | *.iml
4 | Dockerfile
5 | Dockerfile.multistage
6 | Dockerfile.debug
7 | readme.md
--------------------------------------------------------------------------------
/currency-exchange/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 | !**/src/main/**
5 | !**/src/test/**
6 |
7 | ### STS ###
8 | .apt_generated
9 | .classpath
10 | .factorypath
11 | .project
12 | .settings
13 | .springBeans
14 | .sts4-cache
15 |
16 | ### IntelliJ IDEA ###
17 | .idea
18 | *.iws
19 | *.iml
20 | *.ipr
21 |
22 | ### NetBeans ###
23 | /nbproject/private/
24 | /nbbuild/
25 | /dist/
26 | /nbdist/
27 | /.nb-gradle/
28 | build/
29 |
30 | ### VS Code ###
31 | .vscode/
32 |
--------------------------------------------------------------------------------
/currency-exchange/Dockerfile.multistage:
--------------------------------------------------------------------------------
1 | ARG APP_VERSION
2 | FROM ubaidurehman/3cn-parent:${APP_VERSION} as build
3 | LABEL maintainer="urehman.bese16seecs@seecs.edu.pk"
4 | VOLUME /tmp
5 | WORKDIR /
6 | ADD . .
7 | RUN mvn clean install -DskipTests
8 |
9 | FROM openjdk:17-slim
10 | VOLUME /tmp
11 | WORKDIR /
12 | EXPOSE 8000
13 | ARG APP_VERSION
14 | COPY --from=build /target/currency-exchange-${APP_VERSION}.jar service.jar
15 | ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-Dspring.profiles.active=dev","-jar","/service.jar"]
16 |
--------------------------------------------------------------------------------
/currency-exchange/readme.md:
--------------------------------------------------------------------------------
1 | About
2 | =====
3 | - Implement `/from/{from}/to/{to}` end point which get two countries name and return exchange rate between them
4 |
5 | Dependencies
6 | ============
7 | - #### Web (embedded tomcat + MVC)
8 | - spring-boot-starter-web
9 | - #### Data
10 | - spring-boot-starter-data-jpa
11 | - mysql-connector-java
12 | - #### Cloud
13 | - ##### config server
14 | - spring-cloud-starter-config
15 | - ##### Naming Server Client
16 | - spring-cloud-starter-netflix-eureka-client
17 | - ##### Distributed Tracing
18 | - spring-cloud-sleuth-zipkin
19 | - spring-cloud-starter-sleuth
20 | - #### Security
21 | - ##### Spring Security
22 | - spring-cloud-starter-security
23 | - ##### [OAuth2 Resource Server](./../moreinfo.md#Resource-server)
24 | - spring-boot-starter-oauth2-resource-server
25 | - #### Logstash (Sending logs to Logstash)
26 | - logstash-logging-spring-boot-starter
27 | - ### Database Migration (Liquibase)
28 | - liquibase-core
29 | - jackson-module-jaxb-annotations
30 | - #### [Dependencies From Parent](./../moreinfo.md#Dependencies-from-parent)
31 |
32 | [Distributed Tracing](./../moreinfo.md#distributed-tracing)
33 | -----------------------------------------------------------
34 | [ELK Stack](./../moreinfo.md#elk-stack)
35 | ---------------------------------------
36 | [Audience Validation](./../moreinfo.md#audience-validation)
37 | ------------------------
38 |
39 | Run on different port
40 | ---------------------
41 | - Right Click -> run configuration -> arguments -> vm arguments -> add ```-Dserver.port=port-number```
42 |
43 |
44 |
--------------------------------------------------------------------------------
/currency-exchange/src/main/java/com/ubaid/ms/CurrencyExchangeServiceApplication.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms;
2 |
3 | import brave.sampler.Sampler;
4 | import org.springframework.boot.SpringApplication;
5 | import org.springframework.boot.autoconfigure.SpringBootApplication;
6 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
7 | import org.springframework.context.annotation.Bean;
8 | import org.springframework.context.annotation.EnableAspectJAutoProxy;
9 | import org.springframework.scheduling.annotation.EnableScheduling;
10 |
11 | @SpringBootApplication
12 | @EnableDiscoveryClient
13 | @EnableAspectJAutoProxy
14 | @EnableScheduling
15 | public class CurrencyExchangeServiceApplication {
16 |
17 | public static void main(String[] args) {
18 | SpringApplication.run(CurrencyExchangeServiceApplication.class, args);
19 | }
20 |
21 | @Bean
22 | public Sampler defaultSampler() {
23 | return Sampler.ALWAYS_SAMPLE;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/currency-exchange/src/main/java/com/ubaid/ms/currencyexchangeservice/aop/TargetMethods.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.currencyexchangeservice.aop;
2 |
3 | import org.aspectj.lang.annotation.Pointcut;
4 |
5 | public abstract class TargetMethods {
6 |
7 | @Pointcut("execution(* com.ubaid.ms.currencyexchangeservice.service.ExchangeRateService.getExchangeValue(String, String))")
8 | public void getExchangeValue() {}
9 |
10 | @Pointcut("execution(* com.ubaid.ms.currencyexchangeservice.task.PopulateDBWithExchangeRates.populateDbWithExchangeRates())")
11 | public void fetchExchangeRatesFromFixerDotIO() {}
12 | }
--------------------------------------------------------------------------------
/currency-exchange/src/main/java/com/ubaid/ms/currencyexchangeservice/config/Beans.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.currencyexchangeservice.config;
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper;
4 | import org.springframework.beans.factory.config.ConfigurableBeanFactory;
5 | import org.springframework.context.annotation.Bean;
6 | import org.springframework.context.annotation.Scope;
7 |
8 | public class Beans {
9 |
10 | @Bean
11 | @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
12 | public ObjectMapper objectMapper() {
13 | return new ObjectMapper();
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/currency-exchange/src/main/java/com/ubaid/ms/currencyexchangeservice/config/Config.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.currencyexchangeservice.config;
2 |
3 | import lombok.Data;
4 | import lombok.NoArgsConstructor;
5 | import org.springframework.boot.context.properties.ConfigurationProperties;
6 | import org.springframework.stereotype.Component;
7 |
8 | @ConfigurationProperties(prefix = "fixer.io")
9 | @Component
10 | @Data
11 | @NoArgsConstructor
12 | public class Config {
13 | private String baseURL;
14 | private String apiKey;
15 | private String localStoragePath;
16 | }
17 |
--------------------------------------------------------------------------------
/currency-exchange/src/main/java/com/ubaid/ms/currencyexchangeservice/config/validator/AudienceValidator.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.currencyexchangeservice.config.validator;
2 |
3 | import lombok.extern.slf4j.Slf4j;
4 | import org.springframework.security.oauth2.core.OAuth2Error;
5 | import org.springframework.security.oauth2.core.OAuth2TokenValidator;
6 | import org.springframework.security.oauth2.core.OAuth2TokenValidatorResult;
7 | import org.springframework.security.oauth2.jwt.Jwt;
8 |
9 | import static com.ubaid.ms.common.util.Constants.*;
10 |
11 | @Slf4j
12 | public class AudienceValidator implements OAuth2TokenValidator {
13 |
14 | private final OAuth2Error error = new OAuth2Error(INVALID_TOKEN, String.format("The required audience %s is missing", AUD), null);
15 | private final static String AUD = CURRENCY_EXCHANGE_SERVICE;
16 |
17 | @Override
18 | public OAuth2TokenValidatorResult validate(Jwt jwt) {
19 | if (jwt.getAudience().contains(AUD)) {
20 | return OAuth2TokenValidatorResult.success();
21 | } else {
22 | log.error("The required audience {} is missing from the token", AUD);
23 | return OAuth2TokenValidatorResult.failure(error);
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/currency-exchange/src/main/java/com/ubaid/ms/currencyexchangeservice/controller/ExceptionController.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.currencyexchangeservice.controller;
2 |
3 | import com.ubaid.ms.common.dto.ExceptionDTO;
4 | import com.ubaid.ms.common.util.exception.CCException;
5 | import org.springframework.http.HttpStatus;
6 | import org.springframework.http.ResponseEntity;
7 | import org.springframework.web.bind.annotation.ControllerAdvice;
8 | import org.springframework.web.bind.annotation.ExceptionHandler;
9 |
10 | import java.util.Date;
11 |
12 | @ControllerAdvice
13 | public class ExceptionController {
14 |
15 | @ExceptionHandler(CCException.class)
16 | public ResponseEntity handleUnknownException(CCException exp) {
17 | ExceptionDTO exceptionDTO = new ExceptionDTO();
18 | exceptionDTO.setMessage(exp.getMessage());
19 | exceptionDTO.setCause(exp.getCause().toString());
20 | exceptionDTO.setTimeStamp(new Date());
21 | return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(exceptionDTO);
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/currency-exchange/src/main/java/com/ubaid/ms/currencyexchangeservice/controller/InfoController.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.currencyexchangeservice.controller;
2 |
3 | import com.ubaid.ms.common.dto.serviceinfo.ServiceInformation;
4 | import com.ubaid.ms.currencyexchangeservice.service.InfoService;
5 | import lombok.RequiredArgsConstructor;
6 | import org.springframework.http.ResponseEntity;
7 | import org.springframework.web.bind.annotation.GetMapping;
8 | import org.springframework.web.bind.annotation.RequestMapping;
9 | import org.springframework.web.bind.annotation.RestController;
10 |
11 | @RestController
12 | @RequestMapping("v1")
13 | @RequiredArgsConstructor
14 | public class InfoController {
15 | private final InfoService infoService;
16 |
17 | @GetMapping("info")
18 | public ResponseEntity getInfo() {
19 | return ResponseEntity.ok(infoService.get());
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/currency-exchange/src/main/java/com/ubaid/ms/currencyexchangeservice/dao/ExchangeRateDAO.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.currencyexchangeservice.dao;
2 |
3 | import com.ubaid.ms.currencyexchangeservice.entity.ExchangeRate;
4 | import org.springframework.data.jpa.repository.JpaRepository;
5 | import org.springframework.stereotype.Repository;
6 |
7 | import java.util.Optional;
8 |
9 | @Repository
10 | public interface ExchangeRateDAO extends JpaRepository {
11 | Optional findByFromCurrencyAndToCurrency(String from, String to);
12 | }
13 |
--------------------------------------------------------------------------------
/currency-exchange/src/main/java/com/ubaid/ms/currencyexchangeservice/entity/ExchangeRate.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.currencyexchangeservice.entity;
2 |
3 | import lombok.Data;
4 | import lombok.NoArgsConstructor;
5 |
6 | import javax.persistence.*;
7 | import java.util.Date;
8 | import java.util.Objects;
9 |
10 | @Entity
11 | @Table
12 | @Data
13 | @NoArgsConstructor
14 | public class ExchangeRate {
15 | @Id
16 | private String id;
17 | private Date timestamp;
18 | private String fromCurrency;
19 | private String toCurrency;
20 | private Double exchangeRate;
21 |
22 | @Override
23 | public boolean equals(Object o) {
24 | if (this == o) return true;
25 | if (o == null || getClass() != o.getClass()) return false;
26 | ExchangeRate that = (ExchangeRate) o;
27 | return fromCurrency.equals(that.fromCurrency) &&
28 | toCurrency.equals(that.toCurrency);
29 | }
30 |
31 | @Override
32 | public int hashCode() {
33 | return Objects.hash(fromCurrency, toCurrency);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/currency-exchange/src/main/java/com/ubaid/ms/currencyexchangeservice/service/ExchangeRateService.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.currencyexchangeservice.service;
2 |
3 | import com.ubaid.ms.common.dto.ExchangeValueDTO;
4 | import com.ubaid.ms.currencyexchangeservice.entity.ExchangeRate;
5 |
6 | import java.util.List;
7 |
8 | public interface ExchangeRateService {
9 | ExchangeValueDTO getExchangeValue(String from, String to);
10 | void saveAll(List exchangeRates);
11 | }
12 |
--------------------------------------------------------------------------------
/currency-exchange/src/main/java/com/ubaid/ms/currencyexchangeservice/service/InfoService.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.currencyexchangeservice.service;
2 |
3 | import com.ubaid.ms.common.dto.serviceinfo.ServiceInformation;
4 |
5 | public interface InfoService {
6 | ServiceInformation get();
7 | }
8 |
--------------------------------------------------------------------------------
/currency-exchange/src/main/java/com/ubaid/ms/currencyexchangeservice/service/InfoServiceImpl.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.currencyexchangeservice.service;
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper;
4 | import com.netflix.appinfo.ApplicationInfoManager;
5 | import com.ubaid.ms.common.dto.serviceinfo.ServiceInformation;
6 | import com.ubaid.ms.common.dto.serviceinfo.ServiceInformationBuilder;
7 | import lombok.RequiredArgsConstructor;
8 | import lombok.extern.slf4j.Slf4j;
9 | import org.springframework.boot.actuate.info.InfoEndpoint;
10 | import org.springframework.stereotype.Service;
11 |
12 | @Service
13 | @Slf4j
14 | @RequiredArgsConstructor
15 | public class InfoServiceImpl implements InfoService {
16 |
17 | private final InfoEndpoint infoEndpoint;
18 | private final ObjectMapper objectMapper;
19 | private final ApplicationInfoManager applicationInfoManager;
20 |
21 | @Override
22 | public ServiceInformation get() {
23 | ServiceInformationBuilder builder = ServiceInformationBuilder
24 | .builder(objectMapper.convertValue(infoEndpoint.info(), ServiceInformation.class));
25 | builder.name(applicationInfoManager.getInfo().getAppName());
26 | ServiceInformation serviceInformation = builder.build();
27 | log.debug("Service Information: {}", serviceInformation);
28 | return serviceInformation;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/currency-exchange/src/main/java/com/ubaid/ms/currencyexchangeservice/service/ServerInfoService.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.currencyexchangeservice.service;
2 |
3 | public interface ServerInfoService {
4 | int getPort();
5 | String getIPAddress();
6 | }
7 |
--------------------------------------------------------------------------------
/currency-exchange/src/main/java/com/ubaid/ms/currencyexchangeservice/utility/ExchangeRateDTOConverter.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.currencyexchangeservice.utility;
2 |
3 | import com.ubaid.ms.common.dto.ExchangeRateDTO;
4 | import com.ubaid.ms.currencyexchangeservice.entity.ExchangeRate;
5 | import lombok.Getter;
6 |
7 | import java.util.Date;
8 | import java.util.List;
9 | import java.util.stream.Collectors;
10 |
11 | @Getter
12 | public class ExchangeRateDTOConverter {
13 | private final List exchangeRates;
14 | public ExchangeRateDTOConverter(ExchangeRateDTO exchangeRateDTO) {
15 | exchangeRates = convert(exchangeRateDTO);
16 | }
17 |
18 | List convert(ExchangeRateDTO exchangeRateDTO) {
19 | return exchangeRateDTO.getRates().entrySet().stream().map(entry -> {
20 | ExchangeRate exchangeRate = getExchangeRateInitializedWithValues(exchangeRateDTO.getTimestamp(), exchangeRateDTO.getBase());
21 | exchangeRate.setToCurrency(entry.getKey());
22 | exchangeRate.setExchangeRate(entry.getValue());
23 | exchangeRate.setId(exchangeRate.getFromCurrency() + "_" + exchangeRate.getToCurrency());
24 | return exchangeRate;
25 | }).collect(Collectors.toList());
26 | }
27 |
28 | private ExchangeRate getExchangeRateInitializedWithValues(long timestamp, String fromCurrency) {
29 | ExchangeRate exchangeRate = new ExchangeRate();
30 | exchangeRate.setFromCurrency(fromCurrency);
31 | exchangeRate.setTimestamp(new Date(timestamp));
32 | return exchangeRate;
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/currency-exchange/src/main/resources/application-dev.properties:
--------------------------------------------------------------------------------
1 | #------------------------Config Client--------------------------#
2 | spring.config.import=optional:configserver:http://config:8888
3 | spring.cloud.config.profile=dev
4 | spring.cloud.config.fail-fast=true
5 | spring.cloud.config.request-connect-timeout=30000
6 | spring.cloud.config.request-read-timeout=360000
--------------------------------------------------------------------------------
/currency-exchange/src/main/resources/application-local.properties:
--------------------------------------------------------------------------------
1 | #------------------------Config Client--------------------------#
2 | spring.config.import=optional:configserver:http://localhost:8888
3 | spring.cloud.config.profile=local
4 |
5 | #------------------------Live Reload --------------------------#
6 | spring.devtools.livereload.port=35734
7 |
8 | #------------------------Logs --------------------------#
9 | logging.level.org.springframework.cloud.gateway=DEBUG
10 | logging.level.org.springframework.security=DEBUG
11 | logging.level.org.springframework.web.reactive.function.client=DEBUG
12 |
13 | #------------------------Actuator --------------------------#
14 | management.endpoints.web.exposure.include=health,info
15 | management.endpoint.health.enabled=true
16 | management.endpoint.health.probes.enabled=true
--------------------------------------------------------------------------------
/currency-exchange/src/main/resources/application-prod.properties:
--------------------------------------------------------------------------------
1 | #------------------------Config Client--------------------------#
2 | spring.config.import=optional:configserver:http://config:8888
3 | spring.cloud.config.profile=prod
4 | spring.cloud.config.fail-fast=true
5 | spring.cloud.config.request-connect-timeout=30000
6 | spring.cloud.config.request-read-timeout=360000
--------------------------------------------------------------------------------
/currency-exchange/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 | #------------------------App Level Configuration--------------------------#
2 | spring.application.name=currency-exchange
3 | server.port=8000
4 |
5 | #------------------------Active Profile ----------------------------------#
6 | spring.profiles.active=@activatedProperties@
7 |
8 | #------------------------Numeric IP---------------------------------------#
9 | eureka.instance.prefer-ip-address=true
10 | eureka.instance.instance-id=${spring.cloud.client.ip-address}:${server.port}
11 | eureka.instance.hostname=${spring.cloud.client.ip-address}
12 |
13 | #------------------------Disable Warnings---------------------------------#
14 | spring.jpa.open-in-view=false
15 | spring.mvc.pathmatch.matching-strategy=ant_path_matcher
16 | spring.main.allow-circular-references=true
17 |
18 |
19 |
--------------------------------------------------------------------------------
/currency-exchange/src/main/resources/config.properties:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubaid4j/Cloud-Native-App-Spring-Boot/d023b0a732b43f4196176cd9fa3a67490a79eaab/currency-exchange/src/main/resources/config.properties
--------------------------------------------------------------------------------
/currency-exchange/src/main/resources/db/changelog/changes/v00001.sql:
--------------------------------------------------------------------------------
1 | -- liquibase formatted sql
2 | -- changeset ubaid:20Oct2020_2157
3 | -- comment creating exchange rate table
4 | create table exchange_rate(
5 | id varchar(255) primary key,
6 | timestamp datetime,
7 | from_currency varchar(255),
8 | to_currency varchar(255),
9 | exchange_rate double
10 | );
--------------------------------------------------------------------------------
/currency-exchange/src/main/resources/db/changelog/db.changelog-master.yaml:
--------------------------------------------------------------------------------
1 | databaseChangeLog:
2 | - includeAll:
3 | path: db/changelog/changes
--------------------------------------------------------------------------------
/currency-exchange/src/test/java/com/ubaid/ms/currency_conversion_service/ContextTest.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.currency_conversion_service;
2 |
3 | import org.junit.jupiter.api.Test;
4 | import org.springframework.boot.test.context.SpringBootTest;
5 |
6 | @SpringBootTest
7 | public class ContextTest {
8 |
9 | @Test
10 | void loadContext() {
11 |
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/currency-exchange/src/test/java/com/ubaid/ms/currencyexchangeservice/utility/ExchangeRateDTOConverterTest.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.currencyexchangeservice.utility;
2 |
3 | import com.ubaid.ms.common.dto.ExchangeRateDTO;
4 | import com.ubaid.ms.currencyexchangeservice.entity.ExchangeRate;
5 | import com.ubaid.ms.currencyexchangeservice.task.PopulateDBWithExchangeRates;
6 | import org.junit.jupiter.api.DisplayName;
7 | import org.junit.jupiter.api.Test;
8 | import static org.junit.jupiter.api.Assertions.*;
9 | import org.springframework.beans.factory.annotation.Autowired;
10 | import org.springframework.boot.test.context.SpringBootTest;
11 | import org.springframework.context.annotation.Lazy;
12 |
13 | import java.util.List;
14 |
15 | @SpringBootTest
16 | class ExchangeRateDTOConverterTest {
17 |
18 | @Autowired
19 | @Lazy
20 | PopulateDBWithExchangeRates populateDBWithExchangeRates;
21 |
22 | @Test
23 | @DisplayName("Exchange Rate DTO Should convert to list of ExchangeRate")
24 | void convert() {
25 | ExchangeRateDTO exchangeRateDTO = populateDBWithExchangeRates.getResponseData();
26 | ExchangeRateDTOConverter converter = new ExchangeRateDTOConverter(exchangeRateDTO);
27 | List exchangeRates = converter.convert(exchangeRateDTO);
28 | assertNotNull(exchangeRates, "Exchange rates should not be null");
29 | assertTrue(exchangeRates.size() > 150, "There are 168 actual rates. The minimum threshold should be 150");
30 | }
31 | }
--------------------------------------------------------------------------------
/currency-exchange/src/test/resources/application.properties:
--------------------------------------------------------------------------------
1 | #------------------------App Level Configuration--------------------------#
2 | spring.application.name=currency-exchange
3 | server.port=8000
4 |
5 | #------------------------Config Client --------------------------#
6 | spring.config.import=optional:configserver:http://localhost:8888
7 | spring.cloud.config.profile=test
8 |
9 | #------------------------Active Profile --------------------------#
10 | spring.profiles.active=test
11 |
12 | #------------------------Numeric IP-------------------------------#
13 | eureka.instance.prefer-ip-address=true
14 | eureka.instance.instance-id=${spring.cloud.client.ip-address}:${server.port}
15 | eureka.instance.hostname=${spring.cloud.client.ip-address}
16 |
17 | #------------------------Disable Warnings-------------------------#
18 | spring.jpa.open-in-view=false
19 |
20 | #------------------------issuer uri --------------------------#
21 | spring.security.oauth2.resourceserver.jwt.issuer-uri=http://localhost:9898/auth/realms/3cn
22 |
23 |
--------------------------------------------------------------------------------
/discovery/.dockerignore:
--------------------------------------------------------------------------------
1 | /target
2 | .gitignore
3 | *.iml
4 | Dockerfile
5 | Dockerfile.multistage
6 | readme.md
--------------------------------------------------------------------------------
/discovery/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 | !**/src/main/**
5 | !**/src/test/**
6 |
7 | ### STS ###
8 | .apt_generated
9 | .classpath
10 | .factorypath
11 | .project
12 | .settings
13 | .springBeans
14 | .sts4-cache
15 |
16 | ### IntelliJ IDEA ###
17 | .idea
18 | *.iws
19 | *.iml
20 | *.ipr
21 |
22 | ### NetBeans ###
23 | /nbproject/private/
24 | /nbbuild/
25 | /dist/
26 | /nbdist/
27 | /.nb-gradle/
28 | build/
29 |
30 | ### VS Code ###
31 | .vscode/
32 |
--------------------------------------------------------------------------------
/discovery/Dockerfile.multistage:
--------------------------------------------------------------------------------
1 | ARG APP_VERSION
2 | FROM ubaidurehman/3cn-parent:${APP_VERSION} as build
3 | LABEL maintainer="urehman.bese16seecs@seecs.edu.pk"
4 | VOLUME /tmp
5 | WORKDIR /
6 | ADD . .
7 | RUN mvn clean install -DskipTests
8 |
9 | FROM openjdk:17-slim
10 | VOLUME /tmp
11 | WORKDIR /
12 | EXPOSE 8761
13 | ARG APP_VERSION
14 | COPY --from=build /target/discovery-${APP_VERSION}.jar service.jar
15 | ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-Dspring.profiles.active=dev","-jar","/service.jar"]
16 |
--------------------------------------------------------------------------------
/discovery/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 |
5 | com.ubaid.ms
6 | CC-CN-APP
7 | 0.0.3-SNAPSHOT
8 |
9 |
10 | discovery
11 | 0.0.3-SNAPSHOT
12 | Discovery Server
13 | This is Netflix Eureka Discovery Server
14 |
15 |
16 |
17 |
18 | org.springframework.cloud
19 | spring-cloud-starter-netflix-eureka-server
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/discovery/readme.md:
--------------------------------------------------------------------------------
1 | About
2 | =====
3 | - Discovery (Netflix Eureka) Server
4 |
5 | Dependencies
6 | ------------
7 | - #### Cloud
8 | - ##### Discovery Server
9 | - spring-cloud-starter-netflix-eureka-server
10 | - #### [Dependencies From Parent](./../moreinfo.md#Dependencies-from-parent)
11 |
12 | Configurations
13 | --------------
14 | Annotate Application with @EnableEurekaServer
15 |
16 |
--------------------------------------------------------------------------------
/discovery/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 | #-----------------------Application Config------------------------------------------#
2 | spring.application.name=discovery
3 | server.port=8761
4 |
5 | #----------------------Make following statement false as this is not client---------#
6 | eureka.client.register-with-eureka=false
7 | eureka.client.fetch-registry=false
8 |
9 | #----------------------Use Numeric IPs----------------------------------------------#
10 | eureka.instance.prefer-ip-address=true
11 | eureka.instance.instance-id=${spring.cloud.client.ip-address}:${server.port}
12 | eureka.instance.hostname=${spring.cloud.client.ip-address}
13 |
14 |
15 | #----------------------------Disabling warnings ------#
16 | spring.mvc.pathmatch.matching-strategy=ant_path_matcher
17 | spring.main.allow-circular-references=true
18 |
--------------------------------------------------------------------------------
/envcn/.env:
--------------------------------------------------------------------------------
1 | APP_VERSION=0.0.3-SNAPSHOT
2 | ELK_VERSION=7.17.1
3 | RABBIT_MQ=3.9.13-management
4 | ZIPKIN=2.23.16
5 | MY_SQL=8.0.28
6 | KEY_CLOAK=16.1.1
--------------------------------------------------------------------------------
/envcn/auth-db/Dockerfile:
--------------------------------------------------------------------------------
1 | ARG MY_SQL
2 | FROM mysql:${MY_SQL}
3 | COPY ./sql/dump.sql /docker-entrypoint-initdb.d/dump.sql
--------------------------------------------------------------------------------
/envcn/auth-db/buid-push-prod-image.sh:
--------------------------------------------------------------------------------
1 | docker build -t ubaidurehman/auth-db:0.0.3-SNAPSHOT --build-arg MY_SQL=8.0.25 .
2 | docker push ubaidurehman/auth-db:0.0.3-SNAPSHOT
--------------------------------------------------------------------------------
/envcn/db/Dockerfile:
--------------------------------------------------------------------------------
1 | ARG MY_SQL
2 | FROM mysql:${MY_SQL}
3 | COPY init.sql /docker-entrypoint-initdb.d/
--------------------------------------------------------------------------------
/envcn/db/init.sql:
--------------------------------------------------------------------------------
1 | create database if not exists audit_db;
--------------------------------------------------------------------------------
/envcn/elasticsearch/Dockerfile:
--------------------------------------------------------------------------------
1 | ARG ELK_VERSION
2 |
3 | # https://www.docker.elastic.co/
4 | FROM docker.elastic.co/elasticsearch/elasticsearch:${ELK_VERSION}
5 |
6 | # Add your elasticsearch plugins setup here
7 | # Example: RUN elasticsearch-plugin install analysis-icu
8 |
--------------------------------------------------------------------------------
/envcn/elasticsearch/config/elasticsearch.yml:
--------------------------------------------------------------------------------
1 | ---
2 | ## Default Elasticsearch configuration from Elasticsearch base image.
3 | ## https://github.com/elastic/elasticsearch/blob/master/distribution/docker/src/docker/config/elasticsearch.yml
4 | #
5 | cluster.name: "docker-cluster"
6 | network.host: 0.0.0.0
7 |
8 | ## X-Pack settings
9 | ## see https://www.elastic.co/guide/en/elasticsearch/reference/current/setup-xpack.html
10 | #
11 | xpack.license.self_generated.type: trial
12 | xpack.security.enabled: false
13 | xpack.monitoring.collection.enabled: true
14 |
--------------------------------------------------------------------------------
/envcn/kc/Dockerfile:
--------------------------------------------------------------------------------
1 | ARG KEY_CLOAK
2 | FROM jboss/keycloak:${KEY_CLOAK}
--------------------------------------------------------------------------------
/envcn/kibana/Dockerfile:
--------------------------------------------------------------------------------
1 | ARG ELK_VERSION
2 |
3 | # https://www.docker.elastic.co/
4 | FROM docker.elastic.co/kibana/kibana:${ELK_VERSION}
5 |
6 | # Add your kibana plugins setup here
7 | # Example: RUN kibana-plugin install
8 |
--------------------------------------------------------------------------------
/envcn/kibana/config/kibana.yml:
--------------------------------------------------------------------------------
1 | ---
2 | ## Default Kibana configuration from Kibana base image.
3 | ## https://github.com/elastic/kibana/blob/master/src/dev/build/tasks/os_packages/docker_generator/templates/kibana_yml.template.js
4 | #
5 | server.name: kibana
6 | server.host: 0.0.0.0
7 | elasticsearch.hosts: [ "http://elasticsearch:9200" ]
8 | monitoring.ui.container.elasticsearch.enabled: true
9 | ## X-Pack security credentials
10 | #
11 | xpack.security.enabled: false
12 | elasticsearch.username: elastic
13 | elasticsearch.password: changeme
14 |
--------------------------------------------------------------------------------
/envcn/logstash/Dockerfile:
--------------------------------------------------------------------------------
1 | ARG ELK_VERSION
2 |
3 | # https://www.docker.elastic.co/
4 | FROM docker.elastic.co/logstash/logstash:${ELK_VERSION}
5 |
6 | # Add your logstash plugins setup here
7 | # Example: RUN logstash-plugin install logstash-filter-json
8 |
--------------------------------------------------------------------------------
/envcn/logstash/config/logstash.yml:
--------------------------------------------------------------------------------
1 | ---
2 | ## Default Logstash configuration from Logstash base image.
3 | ## https://github.com/elastic/logstash/blob/master/docker/data/logstash/config/logstash-full.yml
4 | #
5 | http.host: "0.0.0.0"
6 | xpack.monitoring.elasticsearch.hosts: [ "http://elasticsearch:9200" ]
7 |
8 | ## X-Pack security credentials
9 | #
10 | xpack.monitoring.enabled: true
11 | xpack.monitoring.elasticsearch.username: elastic
12 | xpack.monitoring.elasticsearch.password: changeme
13 |
--------------------------------------------------------------------------------
/envcn/logstash/pipeline/logstash.conf:
--------------------------------------------------------------------------------
1 | input {
2 | tcp {
3 | port => 5000
4 | }
5 | }
6 |
7 | ## Add your filters / logstash plugins configuration here
8 |
9 | output {
10 | elasticsearch {
11 | hosts => "elasticsearch:9200"
12 | user => "elastic"
13 | password => "changeme"
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/envcn/rabbitmq/Dockerfile:
--------------------------------------------------------------------------------
1 | ARG RABBIT_MQ
2 | FROM rabbitmq:${RABBIT_MQ}
--------------------------------------------------------------------------------
/envcn/run-multi-stage.sh:
--------------------------------------------------------------------------------
1 | docker pull ubaidurehman/3cn-parent:0.0.3-SNAPSHOT;
2 | #Cleaing Database so, that, we can run /docker-entrypoint-initdb.d/init.sql (gh-370)
3 | #If there is data inside the database then /docker-entrypoint-initdb.d/init.sql not running
4 | docker container stop cn-db;
5 | docker container rm cn-db;
6 | docker volume rm envcn_cloud-native-volume;
7 |
8 | #There is a random error (gh-282) when starting auth-server.
9 | #To remove the possibility of gh-282, we are removing auth-db data.
10 | docker container stop auth-db;
11 | docker container rm auth-db;
12 | docker volume rm envcn_auth-db-volume;
13 |
14 | docker-compose -f docker-compose-multi-stage-build.yml up --build
--------------------------------------------------------------------------------
/envcn/zipkin/Dockerfile:
--------------------------------------------------------------------------------
1 | ARG ZIPKIN
2 | FROM openzipkin/zipkin:${ZIPKIN}
--------------------------------------------------------------------------------
/install-maven-jdk17.sh:
--------------------------------------------------------------------------------
1 | #creating custom directory for jdk-17 and maven 3.8.3
2 | sudo mkdir /opt/custom-ubaid
3 | #Deleting Symbolic Links and custom profile for maven
4 | sudo rm -rf /opt/custom-ubaid/java
5 | sudo rm -rf /opt/custom-ubaid/maven
6 | sudo rm -rf /usr/bin/mvn
7 | sudo rm -rf /usr/bin/java
8 | sudo rm -rf /etc/profile.d/custom-ubaid-maven.sh
9 |
10 | # Downloading jdk-17 and extracting
11 | wget https://download.java.net/java/GA/jdk17/0d483333a00540d886896bac774ff48b/35/GPL/openjdk-17_linux-x64_bin.tar.gz -P /tmp
12 | sudo tar -xvf /tmp/openjdk-17_linux-x64_bin.tar.gz -C /opt/custom-ubaid
13 | sudo ln -s /opt/custom-ubaid/jdk-17 /opt/custom-ubaid/java
14 |
15 | # Downloading maven 3.8.3 and extracting
16 | wget https://downloads.apache.org/maven/maven-3/3.8.3/binaries/apache-maven-3.8.3-bin.tar.gz -P /tmp
17 | sudo tar -xvf /tmp/apache-maven-3.8.3-bin.tar.gz -C /opt/custom-ubaid
18 | sudo ln -s /opt/custom-ubaid/apache-maven-3.8.3 /opt/custom-ubaid/maven
19 |
20 | # Creating custom maven profile to point to jdk-17
21 | sudo sh -c "echo export JAVA_HOME=/opt/custom-ubaid/java export MAVEN_HOME=/opt/custom-ubaid/maven export M2_HOME=/opt/custom-ubaid/maven export PATH=/opt/custom-ubaid/maven/bin:${PATH} >> /etc/profile.d/custom-ubaid-maven.sh"
22 | sudo chmod +x /etc/profile.d/custom-ubaid-maven.sh
23 |
24 | # Creating symbolic link for maven and java
25 | sudo ln -s /opt/custom-ubaid/maven/bin/mvn /usr/bin/mvn
26 | sudo ln -s /opt/java/bin/java /usr/bin/java
27 |
28 | # Check mvn version
29 | source /etc/profile.d/custom-ubaid-maven.sh
30 | export JAVA_HOME=/opt/custom-ubaid/java
31 | mvn --version
32 |
--------------------------------------------------------------------------------
/k8s/docx/readme.md:
--------------------------------------------------------------------------------
1 | How to run this Cloud Native Application in Kubernetes
2 | ======================================================
3 |
4 | Requirements
5 | ------------
6 | 1. [Docker](../../resource/install-require-softwares.md#install-docker)
7 | 2. `minikube` and `kubectl` (please execute `k8s/minikube/install_minikube_kubectl.sh` to install both `minikube` and `kubectl`)
8 | 3. Add following lines in your `/etc/hosts` file.
9 | ```
10 | 192.168.49.2 auth-server-io
11 | 192.168.49.2 currency-converter.io
12 | 192.168.49.2 currency-converter.api-gateway.io
13 | ```
14 | Where `192.168.49.2` is the **IP address** of `minikube`. You can check the **IP address** of your `minikube` by executing `minikue ip` command.
15 |
16 | **Warning**: `k8s/minikube/install_minikube_kubectl.sh` delete already existed minikube cluster from your local machine.
17 |
18 | How to run
19 | ----------
20 | Execute the following script and all of **17** services will start running on `minikube` cluster.
21 | * `k8s/k8s-up.sh`
22 |
23 | Kubernetes Dashboard
24 | --------------------
25 | You can access the kubernetes dashboard to check the status of all services just deployed by executing following script
26 | * `minikube dashboard`
27 |
28 | Web UI
29 | -----
30 | As soon all services are up, you can access the following UIs by just clicking on the below links:
31 |
32 | * [Access UI](http://currency-converter.io)
33 | * [Access Swagger](http://currency-converter.api-gateway.io)
34 | * [Access Auth Server](http://auth-server-io)
35 |
36 | Stop all services
37 | -----------------
38 | Just execute the following script to stop all services running in `minikube` cluster.
39 | * `k8s/k8s-down.sh`
40 |
41 | [More Info](moreinfo.md)
42 | ---------
43 |
--------------------------------------------------------------------------------
/k8s/housekeeping/delete-all-configMaps.sh:
--------------------------------------------------------------------------------
1 | kubectl delete -n default configmap kibana-config
2 | kubectl delete -n default configmap logstash-pipeline
3 | kubectl delete -n default configmap logstash-config
4 | kubectl delete -n default configmap elastic-search-config
5 | kubectl delete -n default configmap audit-db-init-config
--------------------------------------------------------------------------------
/k8s/housekeeping/delete-all-deployments.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | declare -a deployments=("api-gateway" "audit" "config" "country" "currency-conversion" "currency-exchange" "discovery" "math" "user" "fe" "elasticsearch" "logstash" "kibana" "rabbit-mq" "zipkin" "auth-db" "auth-server" "app-db")
3 | for deployment in "${deployments[@]}"
4 | do
5 | kubectl delete -n default deployment "$deployment"
6 | done
--------------------------------------------------------------------------------
/k8s/housekeeping/delete-all-ingress.sh:
--------------------------------------------------------------------------------
1 | kubectl delete -n default ingress auth-server
2 | kubectl delete -n default ingress fe
3 | kubectl delete -n default ingress api-gateway
--------------------------------------------------------------------------------
/k8s/housekeeping/delete-all-pv-and-pvc.sh:
--------------------------------------------------------------------------------
1 | kubectl delete -n default persistentvolumeclaim elasticsearch-pvc
2 | kubectl delete persistentvolume elasticsearch-pv
3 |
4 | kubectl delete -n default persistentvolumeclaim mysql-pvc
5 | kubectl delete persistentvolume mysql-pv
6 |
7 | kubectl delete -n default persistentvolumeclaim auth-db-pvc
8 | kubectl delete persistentvolume auth-db-pv
--------------------------------------------------------------------------------
/k8s/housekeeping/delete-all-services.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | declare -a deployments=("api-gateway" "audit" "config" "country" "currency-conversion" "currency-exchange" "discovery" "math" "user" "fe" "elasticsearch" "logstash" "kibana" "rabbitmq" "zipkin" "auth-db" "auth-server-io" "db")
3 | for deployment in "${deployments[@]}"
4 | do
5 | kubectl delete -n default service "$deployment"
6 | done
--------------------------------------------------------------------------------
/k8s/ingress.yml:
--------------------------------------------------------------------------------
1 | apiVersion: networking.k8s.io/v1
2 | kind: Ingress
3 | metadata:
4 | name: auth-server
5 | spec:
6 | rules:
7 | - host: "auth-server-io"
8 | http:
9 | paths:
10 | - pathType: Prefix
11 | path: '/'
12 | backend:
13 | service:
14 | name: auth-server-io
15 | port:
16 | number: 9999
17 | ---
18 |
19 | apiVersion: networking.k8s.io/v1
20 | kind: Ingress
21 | metadata:
22 | name: fe
23 | spec:
24 | rules:
25 | - host: "currency-converter.io"
26 | http:
27 | paths:
28 | - pathType: Prefix
29 | path: '/'
30 | backend:
31 | service:
32 | name: fe
33 | port:
34 | number: 80
35 | ---
36 |
37 | apiVersion: networking.k8s.io/v1
38 | kind: Ingress
39 | metadata:
40 | name: api-gateway
41 | spec:
42 | rules:
43 | - host: "currency-converter.api-gateway.io"
44 | http:
45 | paths:
46 | - pathType: Prefix
47 | path: '/'
48 | backend:
49 | service:
50 | name: api-gateway
51 | port:
52 | number: 8755
53 | ---
--------------------------------------------------------------------------------
/k8s/k8s-down.sh:
--------------------------------------------------------------------------------
1 | ./housekeeping/delete-all-deployments.sh
2 | ./housekeeping/delete-all-configMaps.sh
3 | ./housekeeping/delete-all-pv-and-pvc.sh
4 | ./housekeeping/delete-all-services.sh
5 | ./housekeeping/delete-all-ingress.sh
--------------------------------------------------------------------------------
/k8s/k8s-up.sh:
--------------------------------------------------------------------------------
1 | kubectl apply -f configs.yml
2 | kubectl apply -f pvs.yml
3 | kubectl apply -f pvcs.yml
4 | kubectl apply -f services.yml
5 | kubectl apply -f ingress.yml
6 | kubectl apply -f deployments.yml
--------------------------------------------------------------------------------
/k8s/minikube/install_minikube_kubectl.sh:
--------------------------------------------------------------------------------
1 | #! /bin/sh
2 |
3 | # Minikube update script file
4 | minikube delete
5 | sudo rm -rf /usr/local/bin/minikube
6 | sudo curl -Lo minikube https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
7 | sudo chmod +x minikube
8 | sudo cp minikube /usr/local/bin/
9 | sudo rm minikube
10 | minikube start
11 |
12 | # Enabling addons
13 | minikube addons enable dashboard
14 | minikube addons enable default-storageclass
15 | minikube addons enable storage-provisioner
16 | minikube addons enable ingress
17 |
18 | # Showing enabled addons
19 | printf '\n\n\033[4;33m Enabled Addons \033[0m'
20 | minikube addons list | grep STATUS && minikube addons list | grep enabled && \
21 |
22 | # Showing current status of Minikube
23 | printf '\n\n\033[4;33m Current status of Minikube \033[0m' && minikube status
24 |
25 | printf '\n\n Installing Kubectl'
26 | curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
27 | sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
28 | sudo rm -rf kubectl
--------------------------------------------------------------------------------
/k8s/pvcs.yml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: PersistentVolumeClaim
3 | metadata:
4 | name: auth-db-pvc
5 | spec:
6 | storageClassName: manual
7 | accessModes:
8 | - ReadWriteMany
9 | resources:
10 | requests:
11 | storage: 20Gi
12 | volumeName: auth-db-pv
13 |
14 | ---
15 | apiVersion: v1
16 | kind: PersistentVolumeClaim
17 | metadata:
18 | name: mysql-pvc
19 | spec:
20 | storageClassName: manual
21 | accessModes:
22 | - ReadWriteMany
23 | resources:
24 | requests:
25 | storage: 20Gi
26 | volumeName: mysql-pv
27 |
28 | ---
29 | apiVersion: v1
30 | kind: PersistentVolumeClaim
31 | metadata:
32 | name: elasticsearch-pvc
33 | spec:
34 | storageClassName: manual
35 | accessModes:
36 | - ReadWriteMany
37 | resources:
38 | requests:
39 | storage: 20Gi
40 | volumeName: elasticsearch-pv
41 |
42 |
--------------------------------------------------------------------------------
/k8s/pvs.yml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: PersistentVolume
3 | metadata:
4 | name: auth-db-pv
5 | labels:
6 | type: local
7 | spec:
8 | storageClassName: manual
9 | capacity:
10 | storage: 20Gi
11 | accessModes:
12 | - ReadWriteMany
13 | hostPath:
14 | path: "/mnt/pv/authdb"
15 | ---
16 |
17 | apiVersion: v1
18 | kind: PersistentVolume
19 | metadata:
20 | name: mysql-pv
21 | labels:
22 | type: local
23 | spec:
24 | storageClassName: manual
25 | capacity:
26 | storage: 20Gi
27 | accessModes:
28 | - ReadWriteMany
29 | hostPath:
30 | path: "/mnt/pv/db"
31 | ---
32 |
33 | apiVersion: v1
34 | kind: PersistentVolume
35 | metadata:
36 | name: elasticsearch-pv
37 | labels:
38 | type: local
39 | spec:
40 | storageClassName: manual
41 | capacity:
42 | storage: 20Gi
43 | accessModes:
44 | - ReadWriteMany
45 | hostPath:
46 | path: "/mnt/pv/elasticsearch"
47 | ---
48 |
--------------------------------------------------------------------------------
/math/.dockerignore:
--------------------------------------------------------------------------------
1 | /target
2 | .gitignore
3 | *.iml
4 | Dockerfile
5 | Dockerfile.multistage
6 | readme.md
--------------------------------------------------------------------------------
/math/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 | !**/src/main/**
5 | !**/src/test/**
6 |
7 | ### STS ###
8 | .apt_generated
9 | .classpath
10 | .factorypath
11 | .project
12 | .settings
13 | .springBeans
14 | .sts4-cache
15 |
16 | ### IntelliJ IDEA ###
17 | .idea
18 | *.iws
19 | *.iml
20 | *.ipr
21 |
22 | ### NetBeans ###
23 | /nbproject/private/
24 | /nbbuild/
25 | /dist/
26 | /nbdist/
27 | /.nb-gradle/
28 | build/
29 |
30 | ### VS Code ###
31 | .vscode/
32 |
--------------------------------------------------------------------------------
/math/Dockerfile.multistage:
--------------------------------------------------------------------------------
1 | ARG APP_VERSION
2 | FROM ubaidurehman/3cn-parent:${APP_VERSION} as build
3 | LABEL maintainer="urehman.bese16seecs@seecs.edu.pk"
4 | VOLUME /tmp
5 | WORKDIR /
6 | ADD . .
7 | RUN mvn clean install -DskipTests
8 |
9 | FROM openjdk:17-slim
10 | VOLUME /tmp
11 | WORKDIR /
12 | EXPOSE 8100
13 | ARG APP_VERSION
14 | COPY --from=build /target/math-${APP_VERSION}.jar service.jar
15 | ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-Dspring.profiles.active=dev","-jar","/service.jar"]
16 |
--------------------------------------------------------------------------------
/math/readme.md:
--------------------------------------------------------------------------------
1 | About
2 | =====
3 | - [Math Service](http://localhost:8755/swagger-ui/index.html?urls.primaryName=math)
4 |
5 | Dependencies
6 | ============
7 | - #### Web (embedded tomcat + MVC)
8 | - spring-boot-starter-web
9 | - #### Cloud
10 | - ##### Config Server Client
11 | - spring-cloud-starter-config
12 | - ##### Naming Server Client
13 | - spring-cloud-starter-netflix-eureka-client
14 | - ##### Distributed Tracing
15 | - spring-cloud-sleuth-zipkin
16 | - spring-cloud-starter-sleuth
17 | - #### Security
18 | - ##### Spring Security
19 | - spring-cloud-starter-security
20 | - ##### [OAuth2 Resource Server](./../moreinfo.md#Resource-server)
21 | - spring-boot-starter-oauth2-resource-server
22 | - #### AOP
23 | - spring-boot-starter-aop
24 | - #### Logstash (Sending logs to Logstash)
25 | - logstash-logging-spring-boot-starter
26 | - #### [Dependencies From Parent](./../moreinfo.md#Dependencies-from-parent)
27 |
28 | [Distributed Tracing](./../moreinfo.md#distributed-tracing)
29 | -----------------------------------------------------------
30 | [ELK Stack](./../moreinfo.md#elk-stack)
31 | ---------------------------------------
32 | [Audience Validation](./../moreinfo.md#audience-validation)
33 | ------------------------
34 | Notes
35 | -----
36 | - For deserialization of POJO, we can use @JsonAlias for different names of a field
37 |
--------------------------------------------------------------------------------
/math/src/main/java/com/ubaid/ms/math/MathApplication.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.math;
2 |
3 | import brave.sampler.Sampler;
4 | import org.springframework.boot.SpringApplication;
5 | import org.springframework.boot.autoconfigure.SpringBootApplication;
6 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
7 | import org.springframework.context.annotation.Bean;
8 |
9 |
10 | @SpringBootApplication
11 | @EnableDiscoveryClient
12 | public class MathApplication {
13 |
14 | public static void main(String[] args) {
15 | SpringApplication.run(MathApplication.class, args);
16 | }
17 |
18 | @Bean
19 | public Sampler defaultSampler() {
20 | return Sampler.ALWAYS_SAMPLE;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/math/src/main/java/com/ubaid/ms/math/aop/TargetMethods.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.math.aop;
2 |
3 | import org.aspectj.lang.annotation.Pointcut;
4 |
5 | public abstract class TargetMethods {
6 |
7 | @Pointcut("execution(* com.ubaid.ms.math.service.MathServiceImp.multiply(Double, Double))")
8 | public void convert() {
9 | }
10 | }
--------------------------------------------------------------------------------
/math/src/main/java/com/ubaid/ms/math/config/Beans.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.math.config;
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper;
4 | import org.springframework.beans.factory.config.ConfigurableBeanFactory;
5 | import org.springframework.context.annotation.Bean;
6 | import org.springframework.context.annotation.Scope;
7 |
8 | public class Beans {
9 |
10 | @Bean
11 | @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
12 | public ObjectMapper objectMapper() {
13 | return new ObjectMapper();
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/math/src/main/java/com/ubaid/ms/math/config/validator/AudienceValidator.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.math.config.validator;
2 |
3 | import static com.ubaid.ms.common.util.Constants.INVALID_TOKEN;
4 | import static com.ubaid.ms.common.util.Constants.MATH_SERVICE;
5 |
6 | import lombok.extern.slf4j.Slf4j;
7 | import org.springframework.security.oauth2.core.OAuth2Error;
8 | import org.springframework.security.oauth2.core.OAuth2TokenValidator;
9 | import org.springframework.security.oauth2.core.OAuth2TokenValidatorResult;
10 | import org.springframework.security.oauth2.jwt.Jwt;
11 |
12 | @Slf4j
13 | public class AudienceValidator implements OAuth2TokenValidator {
14 |
15 | private final OAuth2Error error = new OAuth2Error(INVALID_TOKEN, String.format("The required audience %s is missing", AUD), null);
16 | private final static String AUD = MATH_SERVICE;
17 |
18 | @Override
19 | public OAuth2TokenValidatorResult validate(Jwt jwt) {
20 | if (jwt.getAudience().contains(AUD)) {
21 | return OAuth2TokenValidatorResult.success();
22 | } else {
23 | log.error("The required audience {} is missing from the token", AUD);
24 | return OAuth2TokenValidatorResult.failure(error);
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/math/src/main/java/com/ubaid/ms/math/controller/ExceptionController.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.math.controller;
2 |
3 | import com.ubaid.ms.common.dto.ExceptionDTO;
4 | import com.ubaid.ms.common.util.exception.CCException;
5 | import org.springframework.http.HttpStatus;
6 | import org.springframework.http.ResponseEntity;
7 | import org.springframework.web.bind.annotation.ControllerAdvice;
8 | import org.springframework.web.bind.annotation.ExceptionHandler;
9 |
10 | import java.util.Date;
11 |
12 | @ControllerAdvice
13 | public class ExceptionController {
14 |
15 | @ExceptionHandler(CCException.class)
16 | public ResponseEntity handleUnknownException(CCException exp) {
17 | ExceptionDTO exceptionDTO = new ExceptionDTO();
18 | exceptionDTO.setMessage(exp.getMessage());
19 | exceptionDTO.setCause(exp.getCause().toString());
20 | exceptionDTO.setTimeStamp(new Date());
21 | return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(exceptionDTO);
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/math/src/main/java/com/ubaid/ms/math/controller/InfoController.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.math.controller;
2 |
3 | import com.ubaid.ms.common.dto.serviceinfo.ServiceInformation;
4 | import com.ubaid.ms.math.service.InfoService;
5 | import lombok.RequiredArgsConstructor;
6 | import org.springframework.http.ResponseEntity;
7 | import org.springframework.web.bind.annotation.GetMapping;
8 | import org.springframework.web.bind.annotation.RequestMapping;
9 | import org.springframework.web.bind.annotation.RestController;
10 |
11 | @RestController
12 | @RequestMapping("v1")
13 | @RequiredArgsConstructor
14 | public class InfoController {
15 | private final InfoService infoService;
16 |
17 | @GetMapping("info")
18 | public ResponseEntity getInfo() {
19 | return ResponseEntity.ok(infoService.get());
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/math/src/main/java/com/ubaid/ms/math/service/InfoService.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.math.service;
2 |
3 | import com.ubaid.ms.common.dto.serviceinfo.ServiceInformation;
4 |
5 | public interface InfoService {
6 | ServiceInformation get();
7 | }
8 |
--------------------------------------------------------------------------------
/math/src/main/java/com/ubaid/ms/math/service/InfoServiceImpl.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.math.service;
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper;
4 | import com.netflix.appinfo.ApplicationInfoManager;
5 | import com.ubaid.ms.common.dto.serviceinfo.ServiceInformation;
6 | import com.ubaid.ms.common.dto.serviceinfo.ServiceInformationBuilder;
7 | import lombok.RequiredArgsConstructor;
8 | import lombok.extern.slf4j.Slf4j;
9 | import org.springframework.boot.actuate.info.InfoEndpoint;
10 | import org.springframework.stereotype.Service;
11 |
12 | @Service
13 | @Slf4j
14 | @RequiredArgsConstructor
15 | public class InfoServiceImpl implements InfoService {
16 |
17 | private final InfoEndpoint infoEndpoint;
18 | private final ObjectMapper objectMapper;
19 | private final ApplicationInfoManager applicationInfoManager;
20 |
21 | @Override
22 | public ServiceInformation get() {
23 | ServiceInformationBuilder builder = ServiceInformationBuilder
24 | .builder(objectMapper.convertValue(infoEndpoint.info(), ServiceInformation.class));
25 | builder.name(applicationInfoManager.getInfo().getAppName());
26 | ServiceInformation serviceInformation = builder.build();
27 | log.debug("Service Information: {}", serviceInformation);
28 | return serviceInformation;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/math/src/main/java/com/ubaid/ms/math/service/MathService.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.math.service;
2 |
3 |
4 | import com.ubaid.ms.common.dto.ValueDTO;
5 |
6 | public interface MathService {
7 | ValueDTO multiply(Double currency, Double conversionRate);
8 | }
9 |
--------------------------------------------------------------------------------
/math/src/main/java/com/ubaid/ms/math/service/MathServiceImp.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.math.service;
2 |
3 | import com.ubaid.ms.common.dto.ValueDTO;
4 | import lombok.RequiredArgsConstructor;
5 | import org.springframework.stereotype.Service;
6 |
7 | @Service
8 | @RequiredArgsConstructor
9 | public class MathServiceImp implements MathService {
10 |
11 | private final ServerInfoService serverInfo;
12 |
13 | @Override
14 | public ValueDTO multiply(Double currency, Double conversionRate) {
15 | Double resultantValue = currency * conversionRate;
16 |
17 | ValueDTO value = new ValueDTO();
18 | value.setValue(resultantValue);
19 | value.setPort(serverInfo.getPort());
20 | value.setIpAddress(serverInfo.getIPAddress());
21 | return value;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/math/src/main/java/com/ubaid/ms/math/service/ServerInfoService.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.math.service;
2 |
3 | public interface ServerInfoService {
4 | int getPort();
5 | String getIPAddress();
6 | }
7 |
--------------------------------------------------------------------------------
/math/src/main/resources/application-dev.properties:
--------------------------------------------------------------------------------
1 | #------------------------Config Client--------------------------#
2 | spring.config.import=optional:configserver:http://config:8888
3 | spring.cloud.config.profile=dev
4 | spring.cloud.config.fail-fast=true
5 | spring.cloud.config.request-connect-timeout=30000
6 | spring.cloud.config.request-read-timeout=360000
--------------------------------------------------------------------------------
/math/src/main/resources/application-local.properties:
--------------------------------------------------------------------------------
1 | #------------------------Config Client--------------------------#
2 | spring.config.import=optional:configserver:http://localhost:8888
3 | spring.cloud.config.profile=local
4 |
5 | #------------------------Live Reload --------------------------#
6 | spring.devtools.livereload.port=35735
7 |
8 | #------------------------Logs --------------------------#
9 | logging.level.org.springframework.cloud.gateway=DEBUG
10 | logging.level.org.springframework.security=DEBUG
11 | logging.level.org.springframework.web.reactive.function.client=DEBUG
12 |
13 | #------------------------Actuator --------------------------#
14 | management.endpoints.web.exposure.include=health,info
15 | management.endpoint.health.enabled=true
16 | management.endpoint.health.probes.enabled=true
--------------------------------------------------------------------------------
/math/src/main/resources/application-prod.properties:
--------------------------------------------------------------------------------
1 | #------------------------Config Client--------------------------#
2 | spring.config.import=optional:configserver:http://config:8888
3 | spring.cloud.config.profile=prod
4 | spring.cloud.config.fail-fast=true
5 | spring.cloud.config.request-connect-timeout=30000
6 | spring.cloud.config.request-read-timeout=360000
--------------------------------------------------------------------------------
/math/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 | #----------------------------SApplication config-----------------------------------#
2 | spring.application.name=math
3 | server.port=8100
4 |
5 | #----------------------------Active Profile----------------------------------------#
6 | spring.profiles.active=@activatedProperties@
7 |
8 | #----------------------------Static IP---------------------------------------------#
9 | eureka.instance.prefer-ip-address=true
10 | eureka.instance.instance-id=${spring.cloud.client.ip-address}:${server.port}
11 | eureka.instance.hostname=${spring.cloud.client.ip-address}
12 |
13 | #----------------------------Disabling warnings ------#
14 | spring.mvc.pathmatch.matching-strategy=ant_path_matcher
15 | spring.main.allow-circular-references=true
--------------------------------------------------------------------------------
/math/src/main/resources/config.properties:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubaid4j/Cloud-Native-App-Spring-Boot/d023b0a732b43f4196176cd9fa3a67490a79eaab/math/src/main/resources/config.properties
--------------------------------------------------------------------------------
/misc/docker-compose-postgres.yml:
--------------------------------------------------------------------------------
1 | version: '3'
2 | services:
3 | postgresdb:
4 | image: postgres
5 | restart: always
6 | environment:
7 | POSTGRES_USER: 'root'
8 | POSTGRES_PASSWORD: 'password'
9 | ports:
10 | - '3312:5432'
11 | expose:
12 | - '5432'
13 | volumes:
14 | - postgresdbTemp:/var/lib/postgresql/data
15 | networks:
16 | - envcn_cloud-native-network
17 | mongodb:
18 | container_name: cn-mongo-db
19 | image: mongo
20 | environment:
21 | MONGO_INITDB_DATABASE: '3cn_mongo'
22 | MONGO_INITDB_ROOT_USERNAME: 'root'
23 | MONGO_INITDB_ROOT_PASSWORD: 'password'
24 | volumes:
25 | - mongodbTemp:/data/db
26 | ports:
27 | - '27017:27107'
28 | expose:
29 | - '27017'
30 | networks:
31 | - envcn_cloud-native-network
32 | volumes:
33 | postgresdbTemp:
34 | mongodbTemp:
35 | networks:
36 | envcn_cloud-native-network:
37 | external: true
--------------------------------------------------------------------------------
/pull-all-microservice-images.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | declare -a microservices=("api-gateway" "audit" "config" "country" "currency-conversion" "currency-exchange" "discovery" "math" "user")
3 | APP_VERSION=0.0.3-SNAPSHOT
4 | for microservice in "${microservices[@]}"
5 | do
6 | echo pulling ubaidurehman/"$microservice":$APP_VERSION
7 | docker pull ubaidurehman/"$microservice":$APP_VERSION
8 | done
--------------------------------------------------------------------------------
/push-all-microservice-images.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | declare -a microservices=("api-gateway" "audit" "config" "country" "currency-conversion" "currency-exchange" "discovery" "math" "user")
3 | APP_VERSION=0.0.3-SNAPSHOT
4 | for microservice in "${microservices[@]}"
5 | do
6 | echo pushing ubaidurehman/"$microservice":$APP_VERSION
7 | docker push ubaidurehman/"$microservice":$APP_VERSION
8 | done
--------------------------------------------------------------------------------
/resource/3cn-parent-image/readme.md:
--------------------------------------------------------------------------------
1 | ## Building 3cn-parent image
2 | We can build 3cn-parent image from scratch by running `build-3cn-parent-image.sh`
3 | The above script simply install the whole on maven instance. This building requires some time as this project need to download all libraries.
4 | After downloading, it simply creates an image `3cn-parent:0.0.1-SNAPSHOT`
5 |
6 | ## Updating 3cn-parent image
7 | We can update the 3cn-parent image by executing `update-3cn-parent-image`. The above script run the `Dockerfile.update-3cn-parent` which simply reinstall the whole project on `3cn-parent:0.0.1-SNAPSHOT`
8 |
9 | ## Pushing to Dockerhub Registry
10 | `docker push 3cn-parent:0.0.1-SNAPSHOT`
--------------------------------------------------------------------------------
/resource/api-composer-swagger-ui-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubaid4j/Cloud-Native-App-Spring-Boot/d023b0a732b43f4196176cd9fa3a67490a79eaab/resource/api-composer-swagger-ui-2.png
--------------------------------------------------------------------------------
/resource/api-composer-swagger-ui.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubaid4j/Cloud-Native-App-Spring-Boot/d023b0a732b43f4196176cd9fa3a67490a79eaab/resource/api-composer-swagger-ui.png
--------------------------------------------------------------------------------
/resource/auth/3cn-react-client-access-type.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubaid4j/Cloud-Native-App-Spring-Boot/d023b0a732b43f4196176cd9fa3a67490a79eaab/resource/auth/3cn-react-client-access-type.png
--------------------------------------------------------------------------------
/resource/auth/3cn-react-client.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubaid4j/Cloud-Native-App-Spring-Boot/d023b0a732b43f4196176cd9fa3a67490a79eaab/resource/auth/3cn-react-client.png
--------------------------------------------------------------------------------
/resource/auth/auth-flow-v1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubaid4j/Cloud-Native-App-Spring-Boot/d023b0a732b43f4196176cd9fa3a67490a79eaab/resource/auth/auth-flow-v1.png
--------------------------------------------------------------------------------
/resource/auth/auth-flow.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | Detail:
4 | ======
5 | 1. For User End Clients (Like web browser), We have registered a public client (**3cn-react-client**) in KC auth server. When a user login into the web browser, then first it redirects to KC server login page for authentication. When a user provider correct auth credentials (username and password) then KC auth server returns an `access-token` to the end client.
6 | 
7 | 
8 |
9 | 2.This end client will create request to the `resource servers` by appending this `access-token` in `Authorization` header.
10 |
11 | 3.The `resource servers` validate this access token by the help of same `Authorization Server` and then server the request.
12 |
13 |
14 | Validation
15 | ==========
16 | 1. #### User Role Validation
17 | We are validating User Roles in `client` level.
18 | 2. #### Scope Validation
19 | We are validating Scopes in `resource-server` level.
20 | 3. #### Audience Validation
21 | We are validating Audience in `resource-server` level.
--------------------------------------------------------------------------------
/resource/auth/img.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubaid4j/Cloud-Native-App-Spring-Boot/d023b0a732b43f4196176cd9fa3a67490a79eaab/resource/auth/img.png
--------------------------------------------------------------------------------
/resource/auth/img_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubaid4j/Cloud-Native-App-Spring-Boot/d023b0a732b43f4196176cd9fa3a67490a79eaab/resource/auth/img_1.png
--------------------------------------------------------------------------------
/resource/checkstyle/readme.md:
--------------------------------------------------------------------------------
1 | ### Setup Custom checkstyle
2 | 1. Install `CheckStyle-IDEA` plugin in Intellij Idea
3 | 2. Go to `File->Settings->Tools->CheckStyle` and click on `+` under `File Configuration`
4 | 3. Add Description and browser local file to `resource/checkstyle/google_checks.xml`
5 | 4. (Optional) You can activate your custom Checks for whole project, or you can run checks for individual file.
6 |
7 | ### Note:
8 | 1. `google_checks.xml` is cloned from [checkstyle/checkstyle](https://github.com/checkstyle/checkstyle/blob/master/src/main/resources/google_checks.xml)
9 | 2. I have made some modification on `google_checks.xml`
10 | 1. commented out some erroneous modules in `google_checks.xml`
11 | 2. change the indentation level from 2 to 4
--------------------------------------------------------------------------------
/resource/copy-access-token.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubaid4j/Cloud-Native-App-Spring-Boot/d023b0a732b43f4196176cd9fa3a67490a79eaab/resource/copy-access-token.png
--------------------------------------------------------------------------------
/resource/country-service-swagger-ui-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubaid4j/Cloud-Native-App-Spring-Boot/d023b0a732b43f4196176cd9fa3a67490a79eaab/resource/country-service-swagger-ui-2.png
--------------------------------------------------------------------------------
/resource/country-service-swagger-ui.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubaid4j/Cloud-Native-App-Spring-Boot/d023b0a732b43f4196176cd9fa3a67490a79eaab/resource/country-service-swagger-ui.png
--------------------------------------------------------------------------------
/resource/create-index-for-logging.md:
--------------------------------------------------------------------------------
1 | - credentials (It will ask you credentials first)
2 | - username : `elastic`
3 | - password : `changeme`
4 | - First you have to create index `logstash-*` like below graphic.
5 | 
6 | - Select logstash-* index pattern like below graphic and then you will see the logs
7 | 
8 |
--------------------------------------------------------------------------------
/resource/create-index.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubaid4j/Cloud-Native-App-Spring-Boot/d023b0a732b43f4196176cd9fa3a67490a79eaab/resource/create-index.PNG
--------------------------------------------------------------------------------
/resource/definition-drop-down.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubaid4j/Cloud-Native-App-Spring-Boot/d023b0a732b43f4196176cd9fa3a67490a79eaab/resource/definition-drop-down.png
--------------------------------------------------------------------------------
/resource/execute-exchnage-request.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubaid4j/Cloud-Native-App-Spring-Boot/d023b0a732b43f4196176cd9fa3a67490a79eaab/resource/execute-exchnage-request.png
--------------------------------------------------------------------------------
/resource/execute-login-reqeust.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubaid4j/Cloud-Native-App-Spring-Boot/d023b0a732b43f4196176cd9fa3a67490a79eaab/resource/execute-login-reqeust.png
--------------------------------------------------------------------------------
/resource/how-to-user-swagger.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubaid4j/Cloud-Native-App-Spring-Boot/d023b0a732b43f4196176cd9fa3a67490a79eaab/resource/how-to-user-swagger.png
--------------------------------------------------------------------------------
/resource/install-require-softwares.md:
--------------------------------------------------------------------------------
1 | Install Docker
2 | ==============
3 | - [For Ubuntu](https://docs.docker.com/engine/install/ubuntu/)
4 | - [For Mac](https://docs.docker.com/docker-for-mac/install/)
5 | - [For Windows](https://docs.docker.com/docker-for-windows/install/)
6 |
7 |
8 | Install Maven and JDK-17
9 | =======================
10 | - For Linux, simply run the command `./install-maven-jdk17.sh`. It will install `OpenJDK 17` and `Maven 3.8.3`. If you are still seeing the old JDK when executing `mvn --version` then please execute `export JAVA_HOME=/opt/custom-ubaid/java`
11 | - For Mac
12 | - Download [JDK-17 tar.gz from jdk.java.net](https://download.java.net/java/GA/jdk17/0d483333a00540d886896bac774ff48b/35/GPL/openjdk-17_macos-x64_bin.tar.gz)
13 | - Extract it and set `JAVA_HOME` by running `export JAVA_HOME=/path/to/extracted/jdk16/tar`
14 | - Install the latest [Maven 3.8.3](https://downloads.apache.org/maven/maven-3/3.8.3/binaries/apache-maven-3.8.3-bin.tar.gz)
15 | - Set MAVEN_HOME and M2_HOME and are pointing to maven-3.8.1 root directory
16 | - For Windows
17 | - Download [JDK-17 zip from jdk.java.net](https://download.java.net/java/GA/jdk17/0d483333a00540d886896bac774ff48b/35/GPL/openjdk-17_windows-x64_bin.zip)
18 | - Extract it and set `JAVA_HOME` using `Environment Variable`
19 | - Install the latest [Maven 3.8.3](https://downloads.apache.org/maven/maven-3/3.8.3/binaries/apache-maven-3.8.3-bin.tar.gz)
20 | - Set `MAVEN_HOME` and `M2_HOME` using `Environment Variable`
--------------------------------------------------------------------------------
/resource/java-home.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubaid4j/Cloud-Native-App-Spring-Boot/d023b0a732b43f4196176cd9fa3a67490a79eaab/resource/java-home.png
--------------------------------------------------------------------------------
/resource/kibana-dashboard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubaid4j/Cloud-Native-App-Spring-Boot/d023b0a732b43f4196176cd9fa3a67490a79eaab/resource/kibana-dashboard.png
--------------------------------------------------------------------------------
/resource/lucid-diagrams/3cnArchitecture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubaid4j/Cloud-Native-App-Spring-Boot/d023b0a732b43f4196176cd9fa3a67490a79eaab/resource/lucid-diagrams/3cnArchitecture.png
--------------------------------------------------------------------------------
/resource/mvn-version.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubaid4j/Cloud-Native-App-Spring-Boot/d023b0a732b43f4196176cd9fa3a67490a79eaab/resource/mvn-version.png
--------------------------------------------------------------------------------
/resource/pase-acces-token.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubaid4j/Cloud-Native-App-Spring-Boot/d023b0a732b43f4196176cd9fa3a67490a79eaab/resource/pase-acces-token.png
--------------------------------------------------------------------------------
/resource/see-the-response.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubaid4j/Cloud-Native-App-Spring-Boot/d023b0a732b43f4196176cd9fa3a67490a79eaab/resource/see-the-response.png
--------------------------------------------------------------------------------
/resource/swagger-authorize-request.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubaid4j/Cloud-Native-App-Spring-Boot/d023b0a732b43f4196176cd9fa3a67490a79eaab/resource/swagger-authorize-request.png
--------------------------------------------------------------------------------
/run-multi-stage.sh:
--------------------------------------------------------------------------------
1 | docker pull ubaidurehman/3cn-parent:0.0.3-SNAPSHOT;
2 | docker-compose -f docker-compose-multi-stage-build.yml up --build;
--------------------------------------------------------------------------------
/update-3cn-parent-image.sh:
--------------------------------------------------------------------------------
1 | docker build -t ubaidurehman/3cn-parent:0.0.3-SNAPSHOT -f Dockerfile.update-3cn-parent .
2 |
--------------------------------------------------------------------------------
/user/.dockerignore:
--------------------------------------------------------------------------------
1 | /target
2 | .gitignore
3 | user-service.iml
4 | Dockerfile
5 | readme.md
--------------------------------------------------------------------------------
/user/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 | !**/src/main/**/target/
5 | !**/src/test/**/target/
6 |
7 | ### STS ###
8 | .apt_generated
9 | .classpath
10 | .factorypath
11 | .project
12 | .settings
13 | .springBeans
14 | .sts4-cache
15 |
16 | ### IntelliJ IDEA ###
17 | .idea
18 | *.iws
19 | *.iml
20 | *.ipr
21 |
22 | ### NetBeans ###
23 | /nbproject/private/
24 | /nbbuild/
25 | /dist/
26 | /nbdist/
27 | /.nb-gradle/
28 | build/
29 | !**/src/main/**/build/
30 | !**/src/test/**/build/
31 |
32 | ### VS Code ###
33 | .vscode/
34 |
--------------------------------------------------------------------------------
/user/Dockerfile.multistage:
--------------------------------------------------------------------------------
1 | ARG APP_VERSION
2 | FROM ubaidurehman/3cn-parent:${APP_VERSION} as build
3 | LABEL maintainer="urehman.bese16seecs@seecs.edu.pk"
4 | VOLUME /tmp
5 | WORKDIR /
6 | ADD . .
7 | RUN mvn clean install -DskipTests
8 |
9 | FROM openjdk:17-slim
10 | VOLUME /tmp
11 | WORKDIR /
12 | EXPOSE 8900
13 | ARG APP_VERSION
14 | COPY --from=build /target/user-${APP_VERSION}.jar service.jar
15 | ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-Dspring.profiles.active=dev","-jar","/service.jar"]
16 |
--------------------------------------------------------------------------------
/user/readme.md:
--------------------------------------------------------------------------------
1 | About
2 | =====
3 | - [User Service](http://localhost:8755/swagger-ui/index.html?urls.primaryName=user)
4 |
5 | Dependencies
6 | ============
7 | - #### Web Flux
8 | - spring-boot-starter-webflux
9 | - #### Cloud
10 | - ##### Config Server Client
11 | - spring-cloud-starter-config
12 | - ##### Rest Client
13 | - spring-cloud-starter-openfeign
14 | - ##### Naming Server Client
15 | - spring-cloud-starter-netflix-eureka-client
16 | - ##### Distributed Tracing
17 | - spring-cloud-sleuth-zipkin
18 | - spring-cloud-starter-sleuth
19 | - #### Security
20 | - ##### Spring Security
21 | - spring-cloud-starter-security
22 | - ##### [OAuth2 Resource Server](./../moreinfo.md#Resource-server)
23 | - spring-boot-starter-oauth2-resource-server
24 | - ##### Test
25 | - spring-security-test
26 | - #### AOP
27 | - spring-boot-starter-aop
28 | - #### Logstash (Sending logs to Logstash)
29 | - logstash-logging-spring-boot-starter
30 | - #### Test
31 | - reactor-test
32 | - #### [Dependencies From Parent](./../moreinfo.md#Dependencies-from-parent)
33 |
34 | [Distributed Tracing](./../moreinfo.md#distributed-tracing)
35 | -----------------------------------------------------------
36 | [ELK Stack](./../moreinfo.md#elk-stack)
37 | ---------------------------------------
--------------------------------------------------------------------------------
/user/src/main/java/com/ubaid/ms/UserApp.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
6 | import org.springframework.cloud.openfeign.EnableFeignClients;
7 | import org.springframework.context.annotation.EnableAspectJAutoProxy;
8 | import springfox.documentation.oas.annotations.EnableOpenApi;
9 |
10 | import static com.ubaid.ms.common.util.Constants.APP_ROOT_PACKAGE;
11 |
12 | @SpringBootApplication
13 | @EnableFeignClients(basePackages = {APP_ROOT_PACKAGE})
14 | @EnableDiscoveryClient
15 | @EnableAspectJAutoProxy
16 | @EnableOpenApi
17 | public class UserApp {
18 |
19 | public static void main(String[] args) {
20 | SpringApplication.run(UserApp.class, args);
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/user/src/main/java/com/ubaid/ms/user/advice/ExceptionHandlerController.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.user.advice;
2 |
3 | import com.ubaid.ms.common.dto.ExceptionDTO;
4 | import com.ubaid.ms.common.util.exception.CCException;
5 | import org.springframework.http.HttpStatus;
6 | import org.springframework.web.bind.annotation.ExceptionHandler;
7 | import org.springframework.web.bind.annotation.ResponseStatus;
8 | import org.springframework.web.bind.annotation.RestControllerAdvice;
9 | import reactor.core.publisher.Mono;
10 |
11 | import java.util.Date;
12 |
13 | @RestControllerAdvice
14 | public class ExceptionHandlerController {
15 |
16 |
17 | @ExceptionHandler(CCException.class)
18 | @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
19 | public Mono handle3CNException(CCException exp) {
20 |
21 | ExceptionDTO exceptionDTO = new ExceptionDTO();
22 | exceptionDTO.setMessage(exp.getMessage());
23 | exceptionDTO.setCause(exp.getCause().toString());
24 | exceptionDTO.setTimeStamp(new Date());
25 |
26 | return Mono.just(exceptionDTO);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/user/src/main/java/com/ubaid/ms/user/aop/TargetMethods.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.user.aop;
2 |
3 | import org.aspectj.lang.annotation.Pointcut;
4 |
5 | public abstract class TargetMethods {
6 |
7 | @Pointcut("execution(* com.ubaid.ms.user.service.AccessTokenService.getAccessToken(String, String))")
8 | public void getAccessToken() {}
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/user/src/main/java/com/ubaid/ms/user/config/Beans.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.user.config;
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper;
4 | import org.springframework.beans.factory.config.ConfigurableBeanFactory;
5 | import org.springframework.context.annotation.Bean;
6 | import org.springframework.context.annotation.Scope;
7 |
8 | public class Beans {
9 |
10 | @Bean
11 | @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
12 | public ObjectMapper objectMapper() {
13 | return new ObjectMapper();
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/user/src/main/java/com/ubaid/ms/user/controller/InfoController.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.user.controller;
2 |
3 | import com.ubaid.ms.common.dto.serviceinfo.ServiceInformation;
4 | import com.ubaid.ms.user.service.InfoService;
5 | import lombok.RequiredArgsConstructor;
6 | import org.springframework.http.ResponseEntity;
7 | import org.springframework.web.bind.annotation.GetMapping;
8 | import org.springframework.web.bind.annotation.RequestMapping;
9 | import org.springframework.web.bind.annotation.RestController;
10 |
11 | @RestController
12 | @RequestMapping("v1")
13 | @RequiredArgsConstructor
14 | public class InfoController {
15 | private final InfoService infoService;
16 |
17 | @GetMapping("info")
18 | public ResponseEntity getInfo() {
19 | return ResponseEntity.ok(infoService.get());
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/user/src/main/java/com/ubaid/ms/user/controller/UserServiceController.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.user.controller;
2 |
3 | import static com.ubaid.ms.common.util.Constants.*;
4 |
5 | import com.ubaid.ms.common.dto.auth.LoginCred;
6 | import com.ubaid.ms.user.config.SwaggerConfig;
7 | import com.ubaid.ms.user.service.AccessTokenService;
8 | import io.swagger.annotations.*;
9 | import lombok.RequiredArgsConstructor;
10 | import org.springframework.web.bind.annotation.*;
11 | import org.springframework.web.cors.CorsConfiguration;
12 | import reactor.core.publisher.Mono;
13 |
14 | @Api(tags = SwaggerConfig.USER)
15 | @RestController
16 | @RequestMapping("v1")
17 | @RequiredArgsConstructor
18 | @CrossOrigin(value = CorsConfiguration.ALL)
19 | public class UserServiceController {
20 |
21 | private final AccessTokenService tokenService;
22 |
23 | @ApiOperation(value = "Fetch access token for the user credentials (username & password)", response = String.class)
24 | @ApiResponses({
25 | @ApiResponse(code = HTTP_OK, message = "Access Token fetched successfully"),
26 | @ApiResponse(code = HTTP_UNAUTHORIZED, message = "Wrong User Credentials")
27 | })
28 | @PostMapping(value = "oauth/token", consumes = APPLICATION_JSON, produces = TEXT_PLAIN)
29 | public Mono getAccessToken(@RequestBody LoginCred loginCred) {
30 | String accessToken = tokenService.getAccessToken(loginCred.getUsername(), loginCred.getPassword());
31 | return Mono.just(accessToken);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/user/src/main/java/com/ubaid/ms/user/feignproxy/AuthTokenServiceProxy.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.user.feignproxy;
2 |
3 | import feign.codec.Decoder;
4 | import feign.codec.Encoder;
5 | import feign.form.spring.SpringFormEncoder;
6 | import org.springframework.beans.factory.ObjectFactory;
7 | import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
8 | import org.springframework.cloud.openfeign.FeignClient;
9 | import org.springframework.cloud.openfeign.support.SpringDecoder;
10 | import org.springframework.cloud.openfeign.support.SpringEncoder;
11 | import org.springframework.context.annotation.Bean;
12 | import org.springframework.context.annotation.Configuration;
13 | import org.springframework.web.bind.annotation.PostMapping;
14 | import org.springframework.web.bind.annotation.RequestBody;
15 |
16 | import java.util.Map;
17 |
18 | import static org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED_VALUE;
19 |
20 | @FeignClient(name = "auth-server", url = "${keycloak.auth-server-url}", configuration = AuthTokenServiceProxy.FeignResponseDecoderConfig.class)
21 | public interface AuthTokenServiceProxy {
22 |
23 | @PostMapping(value = "/realms/3cn/protocol/openid-connect/token", consumes = APPLICATION_FORM_URLENCODED_VALUE)
24 | Map getAccessToken(@RequestBody Map form);
25 |
26 | @Configuration
27 | class FeignResponseDecoderConfig {
28 | ObjectFactory messageConverters = HttpMessageConverters::new;
29 |
30 | @Bean
31 | Encoder feignFormEncoder() {
32 | return new SpringFormEncoder(new SpringEncoder(messageConverters));
33 | }
34 |
35 | @Bean
36 | Decoder feignFormDecoder() {
37 | return new SpringDecoder(messageConverters);
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/user/src/main/java/com/ubaid/ms/user/service/AccessTokenService.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.user.service;
2 |
3 | /**
4 | * get the access token from the keycloak
5 | * @author ubaid
6 | */
7 | public interface AccessTokenService {
8 | String getAccessToken(String username, String password);
9 | }
10 |
--------------------------------------------------------------------------------
/user/src/main/java/com/ubaid/ms/user/service/AccessTokenServiceImpl.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.user.service;
2 |
3 |
4 | import com.ubaid.ms.user.feignproxy.AuthTokenServiceProxy;
5 | import lombok.RequiredArgsConstructor;
6 | import org.springframework.stereotype.Service;
7 |
8 | import java.util.HashMap;
9 | import java.util.Map;
10 |
11 | @Service
12 | @RequiredArgsConstructor
13 | public class AccessTokenServiceImpl implements AccessTokenService {
14 |
15 | private static final String GRANT_TYPE = "grant_type";
16 | private static final String CLIENT_ID = "client_id";
17 | private static final String USERNAME = "username";
18 | private static final String PASSWORD = "password";
19 |
20 | private final AuthTokenServiceProxy authProxy;
21 |
22 | @Override
23 | public String getAccessToken(String username, String password) {
24 | Map form = new HashMap<>();
25 | form.put(GRANT_TYPE, "password");
26 | form.put(CLIENT_ID, "3cn-react-client");
27 | form.put(USERNAME, username);
28 | form.put(PASSWORD, password);
29 | return String.valueOf(authProxy.getAccessToken(form).get("access_token"));
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/user/src/main/java/com/ubaid/ms/user/service/InfoService.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.user.service;
2 |
3 | import com.ubaid.ms.common.dto.serviceinfo.ServiceInformation;
4 |
5 | public interface InfoService {
6 | ServiceInformation get();
7 | }
8 |
--------------------------------------------------------------------------------
/user/src/main/java/com/ubaid/ms/user/service/InfoServiceImpl.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.user.service;
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper;
4 | import com.netflix.appinfo.ApplicationInfoManager;
5 | import com.ubaid.ms.common.dto.serviceinfo.ServiceInformation;
6 | import com.ubaid.ms.common.dto.serviceinfo.ServiceInformationBuilder;
7 | import lombok.RequiredArgsConstructor;
8 | import lombok.extern.slf4j.Slf4j;
9 | import org.springframework.boot.actuate.info.InfoEndpoint;
10 | import org.springframework.stereotype.Service;
11 |
12 | @Service
13 | @Slf4j
14 | @RequiredArgsConstructor
15 | public class InfoServiceImpl implements InfoService {
16 |
17 | private final InfoEndpoint infoEndpoint;
18 | private final ObjectMapper objectMapper;
19 | private final ApplicationInfoManager applicationInfoManager;
20 |
21 | @Override
22 | public ServiceInformation get() {
23 | ServiceInformationBuilder builder = ServiceInformationBuilder
24 | .builder(objectMapper.convertValue(infoEndpoint.info(), ServiceInformation.class));
25 | builder.name(applicationInfoManager.getInfo().getAppName());
26 | ServiceInformation serviceInformation = builder.build();
27 | log.debug("Service Information: {}", serviceInformation);
28 | return serviceInformation;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/user/src/main/resources/application-dev.properties:
--------------------------------------------------------------------------------
1 | #------------------------Config Client--------------------------#
2 | spring.config.import=optional:configserver:http://config:8888
3 | spring.cloud.config.profile=dev
4 | spring.cloud.config.fail-fast=true
5 | spring.cloud.config.request-connect-timeout=30000
6 | spring.cloud.config.request-read-timeout=360000
--------------------------------------------------------------------------------
/user/src/main/resources/application-local.properties:
--------------------------------------------------------------------------------
1 | #------------------------Config Client--------------------------#
2 | spring.config.import=optional:configserver:http://localhost:8888
3 | spring.cloud.config.profile=local
4 |
5 | #------------------------Live Reload --------------------------#
6 | spring.devtools.livereload.port=35736
7 |
8 | #------------------------Logs --------------------------#
9 | logging.level.org.springframework.security=DEBUG
10 | #logging.level.org.springframework.web.reactive.function.client=DEBUG
11 | logging.level.com.ubaid.ms.userservice.aop=DEBUG
12 |
13 |
14 | #------------------------Actuator --------------------------#
15 | management.endpoints.web.exposure.include=health,info
16 | management.endpoint.health.enabled=true
17 | management.endpoint.health.probes.enabled=true
--------------------------------------------------------------------------------
/user/src/main/resources/application-prod.properties:
--------------------------------------------------------------------------------
1 | #------------------------Config Client--------------------------#
2 | spring.config.import=optional:configserver:http://config:8888
3 | spring.cloud.config.profile=prod
4 | spring.cloud.config.fail-fast=true
5 | spring.cloud.config.request-connect-timeout=30000
6 | spring.cloud.config.request-read-timeout=360000
--------------------------------------------------------------------------------
/user/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 | #----------------------------SApplication config-----------------------------------#
2 | spring.application.name=user
3 | server.port=8900
4 |
5 | #----------------------------Active Profile----------------------------------------#
6 | spring.profiles.active=@activatedProperties@
7 |
8 | #----------------------------Static IP---------------------------------------------#
9 | eureka.instance.prefer-ip-address=true
10 | eureka.instance.instance-id=${spring.cloud.client.ip-address}:${server.port}
11 | eureka.instance.hostname=${spring.cloud.client.ip-address}
12 |
--------------------------------------------------------------------------------
/user/src/main/resources/config.properties:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ubaid4j/Cloud-Native-App-Spring-Boot/d023b0a732b43f4196176cd9fa3a67490a79eaab/user/src/main/resources/config.properties
--------------------------------------------------------------------------------
/user/src/test/java/com/ubaid/ms/userservice/UserAppTests.java:
--------------------------------------------------------------------------------
1 | package com.ubaid.ms.userservice;
2 |
3 | import org.junit.jupiter.api.Test;
4 | import org.springframework.boot.test.context.SpringBootTest;
5 |
6 | @SpringBootTest
7 | class UserAppTests {
8 |
9 | @Test
10 | void contextLoads() {
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------