├── .travis.yml ├── scoring ├── adapters-input │ └── src │ │ └── main │ │ ├── resources │ │ ├── application.properties │ │ └── static │ │ │ ├── index.html │ │ │ └── app.js │ │ └── java │ │ └── com │ │ └── mploed │ │ └── dddwithspring │ │ └── scoring │ │ ├── web │ │ ├── WebSocketMessage.java │ │ └── WebSocketController.java │ │ ├── incoming │ │ ├── realEstate │ │ │ ├── Interior.java │ │ │ ├── ParkingSpace.java │ │ │ ├── Construction.java │ │ │ ├── TypeOfUse.java │ │ │ ├── Attic.java │ │ │ ├── Basement.java │ │ │ ├── UsageOfLoan.java │ │ │ ├── ObjectType.java │ │ │ ├── ApartmentLocation.java │ │ │ ├── Feature.java │ │ │ └── ApartmentInformation.java │ │ ├── AgencyMessage.java │ │ ├── applicant │ │ │ ├── MaritalStatus.java │ │ │ ├── Employment.java │ │ │ ├── Business.java │ │ │ ├── Address.java │ │ │ └── Applicant.java │ │ ├── financing │ │ │ ├── OwnResources.java │ │ │ ├── PurchaseCosts.java │ │ │ ├── Loan.java │ │ │ └── Financing.java │ │ ├── creditAgency │ │ │ └── AgencyRating.java │ │ ├── AgencyResultArrivedEvent.java │ │ ├── household │ │ │ ├── MonthlyExpenses.java │ │ │ ├── EarningCapacity.java │ │ │ └── Household.java │ │ └── ApplicationSubmittedEvent.java │ │ ├── messaging │ │ ├── ApplicationProcessChannels.java │ │ ├── SpringEventListener.java │ │ └── IncomingMessageListener.java │ │ ├── WebSocketConfig.java │ │ ├── InputAdaptersConfiguration.java │ │ └── feeds │ │ └── CreditAgencyPoller.java ├── aggregates │ ├── src │ │ ├── main │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── mploed │ │ │ │ └── dddwithspring │ │ │ │ └── scoring │ │ │ │ ├── scoringResult │ │ │ │ ├── ScoringColor.java │ │ │ │ ├── OverallScoringResult.java │ │ │ │ ├── ScoringResultRootEntity.java │ │ │ │ ├── ScoringCalculationResults.java │ │ │ │ └── ScoringResultAggregate.java │ │ │ │ ├── financialSituation │ │ │ │ ├── Outgoings.java │ │ │ │ ├── Incomings.java │ │ │ │ ├── FinancialSituationRootEntity.java │ │ │ │ └── FinancialSituationAggregate.java │ │ │ │ ├── agencyResult │ │ │ │ ├── KoCriteria.java │ │ │ │ ├── WarningMessage.java │ │ │ │ ├── AgencyResultRootEntity.java │ │ │ │ └── AgencyResultAggregate.java │ │ │ │ └── applicant │ │ │ │ ├── AccountBalance.java │ │ │ │ ├── Address.java │ │ │ │ └── ApplicantAggregate.java │ │ └── test │ │ │ ├── resources │ │ │ └── com │ │ │ │ └── mploed │ │ │ │ └── dddwithspring │ │ │ │ └── scoring │ │ │ │ └── archunit │ │ │ │ └── scoring.puml │ │ │ └── java │ │ │ └── com │ │ │ └── mploed │ │ │ └── dddwithspring │ │ │ └── scoring │ │ │ ├── agencyResult │ │ │ └── AgencyResultTest.java │ │ │ └── archunit │ │ │ └── AggregateArchitectureTest.java │ ├── jqassistant │ │ └── my-rules.xml │ └── pom.xml ├── microarchitecture │ ├── src │ │ └── main │ │ │ └── java │ │ │ └── com │ │ │ └── mploed │ │ │ └── dddwithspring │ │ │ └── scoring │ │ │ └── microarchitecture │ │ │ ├── Aggregate.java │ │ │ └── AggregateBuilder.java │ └── pom.xml ├── adapters-output │ └── src │ │ ├── test │ │ └── java │ │ │ └── com │ │ │ └── mploed │ │ │ └── dddwithspring │ │ │ └── scoring │ │ │ ├── SpringBootTestApplication.java │ │ │ └── AgencyResultRepositoryTest.java │ │ └── main │ │ └── java │ │ └── com │ │ └── mploed │ │ └── dddwithspring │ │ └── scoring │ │ ├── agencyResult │ │ ├── AgencyResultDAO.java │ │ ├── AgencyMessage.java │ │ ├── AgencyResultProjection.java │ │ └── AgencyResultJPARepository.java │ │ ├── scoringResult │ │ ├── ScoringResultDAO.java │ │ ├── DetailedScoringResults.java │ │ ├── ScoringResultEntity.java │ │ └── ScoringResultJPARepository.java │ │ ├── financialSituation │ │ ├── FinancialSituationResultDAO.java │ │ ├── FinancialSituationResultProjection.java │ │ └── FinancialSituationResultJPARepository.java │ │ └── applicant │ │ ├── ApplicantResultDAO.java │ │ ├── ApplicantResultProjection.java │ │ └── ApplicantResultJPARepository.java ├── sharedmodel │ ├── src │ │ ├── main │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── mploed │ │ │ │ └── dddwithspring │ │ │ │ └── scoring │ │ │ │ ├── ApplicationNumber.java │ │ │ │ ├── Money.java │ │ │ │ └── PersonId.java │ │ └── test │ │ │ └── java │ │ │ └── com │ │ │ └── mploed │ │ │ └── dddwithspring │ │ │ └── scoring │ │ │ └── MoneyTest.java │ └── pom.xml ├── scoring-application │ └── src │ │ └── main │ │ ├── resources │ │ └── application.properties │ │ └── java │ │ └── com │ │ └── mploed │ │ └── dddwithspring │ │ └── scoring │ │ └── ScoringApplication.java ├── Dockerfile ├── application-services │ ├── src │ │ └── main │ │ │ └── java │ │ │ └── com │ │ │ └── mploed │ │ │ └── dddwithspring │ │ │ └── scoring │ │ │ └── appservices │ │ │ ├── repositories │ │ │ ├── AgencyResultRepository.java │ │ │ ├── ScoringResultRepository.java │ │ │ ├── FinancialSituationResultRepository.java │ │ │ └── ApplicantResultRepository.java │ │ │ ├── internalevents │ │ │ ├── CreditAgencyResultArrived.java │ │ │ ├── CreditApplicationArrived.java │ │ │ ├── PartOfScoringPerformed.java │ │ │ └── ScoringPerformed.java │ │ │ └── dto │ │ │ ├── FinancialSituation.java │ │ │ ├── Applicant.java │ │ │ └── CreditApplication.java │ └── pom.xml └── pom.xml ├── assets ├── src │ ├── main │ │ ├── resources │ │ │ ├── application.properties │ │ │ └── static │ │ │ │ ├── cssAssets.html │ │ │ │ └── jsAssets.html │ │ └── java │ │ │ └── com │ │ │ └── mploed │ │ │ └── dddwithspring │ │ │ └── assets │ │ │ └── AssetsApplication.java │ └── test │ │ └── java │ │ └── com │ │ └── mploed │ │ └── dddwithspring │ │ └── assets │ │ └── AssetsApplicationTests.java ├── .mvn │ └── wrapper │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── .gitignore └── pom.xml ├── .mvn └── wrapper │ ├── maven-wrapper.jar │ └── maven-wrapper.properties ├── infrastructure_varnish ├── start ├── default.vcl └── Dockerfile ├── credit-sales-funnel ├── src │ └── main │ │ ├── resources │ │ ├── static │ │ │ └── BigPugLoans.jpg │ │ ├── application.properties │ │ └── templates │ │ │ ├── index.html │ │ │ └── layout │ │ │ ├── baseIndex.html │ │ │ └── baseLayout.html │ │ └── java │ │ └── com │ │ └── mploed │ │ └── dddwithspring │ │ └── creditsalesfunnel │ │ ├── model │ │ ├── validation │ │ │ └── ApplicationSubmissionGroup.java │ │ ├── realEstate │ │ │ ├── Interior.java │ │ │ ├── ParkingSpace.java │ │ │ ├── Construction.java │ │ │ ├── TypeOfUse.java │ │ │ ├── Attic.java │ │ │ ├── Basement.java │ │ │ ├── UsageOfLoan.java │ │ │ ├── ObjectType.java │ │ │ ├── ApartmentLocation.java │ │ │ ├── Feature.java │ │ │ └── ApartmentInformation.java │ │ ├── applicant │ │ │ ├── MaritalStatus.java │ │ │ ├── Employment.java │ │ │ ├── Business.java │ │ │ └── Address.java │ │ ├── financing │ │ │ ├── OwnResources.java │ │ │ ├── PurchaseCosts.java │ │ │ ├── Loan.java │ │ │ └── Financing.java │ │ ├── CreditApplicationForm.java │ │ └── household │ │ │ ├── EarningCapacity.java │ │ │ ├── MonthlyExpenses.java │ │ │ └── Household.java │ │ ├── event │ │ ├── CreditSalesFunnelChannels.java │ │ └── CreditApplicationSubmittedEvent.java │ │ ├── repository │ │ ├── FinancingRepository.java │ │ ├── HouseholdRepository.java │ │ ├── RealEstatePropertyRepository.java │ │ └── ApplicantRepository.java │ │ └── CreditSalesFunnelApplication.java └── Dockerfile ├── credit-agency ├── src │ └── main │ │ ├── resources │ │ └── application.properties │ │ └── java │ │ └── com │ │ └── mploed │ │ └── dddwithspring │ │ └── creditagency │ │ ├── messaging │ │ ├── CreditAgencyChannels.java │ │ └── IncomingMessageListener.java │ │ ├── events │ │ └── incoming │ │ │ ├── applicant │ │ │ ├── MaritalStatus.java │ │ │ ├── Employment.java │ │ │ ├── Business.java │ │ │ ├── Address.java │ │ │ └── Applicant.java │ │ │ └── ApplicationSubmittedEvent.java │ │ ├── repository │ │ └── PersonRatingRepository.java │ │ ├── CreditAgencyApplication.java │ │ ├── web │ │ ├── PersonRatingRestController.java │ │ ├── PersonRatingController.java │ │ └── PersonRatingAtomFeedView.java │ │ ├── model │ │ ├── RatingModel.java │ │ └── PersonRating.java │ │ └── service │ │ └── PersonRatingQueryService.java └── Dockerfile ├── pom.xml ├── .gitignore ├── README.md └── docker-compose.yml /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | jdk: openjdk8 -------------------------------------------------------------------------------- /scoring/adapters-input/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.servlet.context-path=/scoring/* -------------------------------------------------------------------------------- /assets/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.port=9003 2 | server.servlet.context-path=/assets 3 | -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mploed/ddd-with-spring/HEAD/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /assets/src/main/resources/static/cssAssets.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /infrastructure_varnish/start: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | varnishd -f /etc/varnish/default.vcl -s malloc,200M -a 0.0.0.0:8080 3 | varnishlog -------------------------------------------------------------------------------- /assets/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mploed/ddd-with-spring/HEAD/assets/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.3/apache-maven-3.5.3-bin.zip 2 | -------------------------------------------------------------------------------- /assets/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip 2 | -------------------------------------------------------------------------------- /credit-sales-funnel/src/main/resources/static/BigPugLoans.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mploed/ddd-with-spring/HEAD/credit-sales-funnel/src/main/resources/static/BigPugLoans.jpg -------------------------------------------------------------------------------- /scoring/aggregates/src/main/java/com/mploed/dddwithspring/scoring/scoringResult/ScoringColor.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.scoringResult; 2 | 3 | enum ScoringColor { 4 | GREEN, YELLOW, RED 5 | } 6 | -------------------------------------------------------------------------------- /assets/src/main/resources/static/jsAssets.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /credit-sales-funnel/src/main/java/com/mploed/dddwithspring/creditsalesfunnel/model/validation/ApplicationSubmissionGroup.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.creditsalesfunnel.model.validation; 2 | 3 | public interface ApplicationSubmissionGroup { 4 | } 5 | -------------------------------------------------------------------------------- /scoring/microarchitecture/src/main/java/com/mploed/dddwithspring/scoring/microarchitecture/Aggregate.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.microarchitecture; 2 | 3 | import java.lang.annotation.*; 4 | 5 | @Target(ElementType.TYPE) 6 | @Documented 7 | public @interface Aggregate { 8 | } 9 | -------------------------------------------------------------------------------- /credit-agency/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.port=9002 2 | management.security.enabled=false 3 | spring.jpa.show-sql=true 4 | 5 | spring.cloud.stream.bindings.applicationSubmittedIn.destination=CreditApplicationSubmittedTopic 6 | spring.cloud.stream.bindings.applicationSubmittedIn.contentType=application/json 7 | -------------------------------------------------------------------------------- /credit-sales-funnel/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.port=9000 2 | management.security.enabled=false 3 | spring.jpa.show-sql=true 4 | 5 | spring.cloud.stream.bindings.creditApplicationSubmittedOut.destination=CreditApplicationSubmittedTopic 6 | spring.cloud.stream.bindings.creditApplicationSubmittedOut.contentType=application/json 7 | -------------------------------------------------------------------------------- /scoring/adapters-output/src/test/java/com/mploed/dddwithspring/scoring/SpringBootTestApplication.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring; 2 | 3 | import org.springframework.boot.autoconfigure.SpringBootApplication; 4 | 5 | @SpringBootApplication(scanBasePackages = "com.mploed.dddwithspring") 6 | public class SpringBootTestApplication { 7 | } 8 | -------------------------------------------------------------------------------- /scoring/adapters-output/src/main/java/com/mploed/dddwithspring/scoring/agencyResult/AgencyResultDAO.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.agencyResult; 2 | 3 | 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | interface AgencyResultDAO extends JpaRepository { 7 | AgencyResultProjection findByPersonId(String personId); 8 | } 9 | -------------------------------------------------------------------------------- /scoring/adapters-output/src/main/java/com/mploed/dddwithspring/scoring/scoringResult/ScoringResultDAO.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.scoringResult; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | 5 | interface ScoringResultDAO extends JpaRepository { 6 | ScoringResultEntity findByApplicationNumber(String applicationNumber); 7 | } 8 | -------------------------------------------------------------------------------- /credit-agency/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:8-jdk-alpine 2 | LABEL maintainer="michael.ploed@innoq.com" 3 | VOLUME /tmp 4 | ENV JAVA_OPTS="" 5 | ENV SPRING_APPLICATION_JSON='{"spring": {"rabbitmq": {"host": "localrabbit", "addresses": "rabbit-mq"}}}' 6 | ENTRYPOINT exec java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar 7 | EXPOSE 9002 8 | ADD target/credit-agency-0.0.1-SNAPSHOT.jar app.jar 9 | -------------------------------------------------------------------------------- /scoring/aggregates/src/main/java/com/mploed/dddwithspring/scoring/scoringResult/OverallScoringResult.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.scoringResult; 2 | 3 | class OverallScoringResult { 4 | final int points; 5 | final ScoringColor color; 6 | 7 | public OverallScoringResult(int points, ScoringColor color) { 8 | this.points = points; 9 | this.color = color; 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /credit-sales-funnel/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:8-jdk-alpine 2 | LABEL maintainer="michael.ploed@innoq.com" 3 | VOLUME /tmp 4 | ENV SPRING_APPLICATION_JSON='{"spring": {"rabbitmq": {"host": "localrabbit", "addresses": "rabbit-mq"}}}' 5 | ENV JAVA_OPTS="" 6 | ENTRYPOINT exec java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar 7 | EXPOSE 9001 8 | ADD target/credit-sales-funnel-0.0.1-SNAPSHOT.jar app.jar 9 | -------------------------------------------------------------------------------- /scoring/microarchitecture/src/main/java/com/mploed/dddwithspring/scoring/microarchitecture/AggregateBuilder.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.microarchitecture; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Target; 6 | 7 | @Target(ElementType.TYPE) 8 | @Documented 9 | public @interface AggregateBuilder { 10 | } 11 | -------------------------------------------------------------------------------- /credit-sales-funnel/src/main/java/com/mploed/dddwithspring/creditsalesfunnel/event/CreditSalesFunnelChannels.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.creditsalesfunnel.event; 2 | 3 | import org.springframework.cloud.stream.annotation.Output; 4 | import org.springframework.messaging.MessageChannel; 5 | 6 | public interface CreditSalesFunnelChannels { 7 | 8 | @Output 9 | MessageChannel creditApplicationSubmittedOut(); 10 | 11 | } 12 | -------------------------------------------------------------------------------- /scoring/adapters-input/src/main/java/com/mploed/dddwithspring/scoring/web/WebSocketMessage.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.web; 2 | 3 | public class WebSocketMessage { 4 | private String content; 5 | 6 | public WebSocketMessage(String content) { 7 | this.content = content; 8 | } 9 | 10 | public WebSocketMessage() { 11 | } 12 | 13 | public String getContent() { 14 | return content; 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /scoring/sharedmodel/src/main/java/com/mploed/dddwithspring/scoring/ApplicationNumber.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring; 2 | 3 | public class ApplicationNumber { 4 | private String applicationNumber; 5 | 6 | public ApplicationNumber(String applicationNumber) { 7 | this.applicationNumber = applicationNumber; 8 | } 9 | 10 | @Override 11 | public String toString() { 12 | return applicationNumber; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /scoring/scoring-application/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.port=9001 2 | server.servlet.context-path=/scoring 3 | management.security.enabled=false 4 | spring.jpa.show-sql=true 5 | 6 | spring.cloud.stream.bindings.applicationSubmittedIn.destination=CreditApplicationSubmittedTopic 7 | spring.cloud.stream.bindings.applicationSubmittedIn.contentType=application/json 8 | 9 | creditAgencyFeed=http://localhost:9002/person-rating/feed -------------------------------------------------------------------------------- /assets/src/main/java/com/mploed/dddwithspring/assets/AssetsApplication.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.assets; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class AssetsApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(AssetsApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /scoring/adapters-output/src/main/java/com/mploed/dddwithspring/scoring/financialSituation/FinancialSituationResultDAO.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.financialSituation; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | 5 | public interface FinancialSituationResultDAO extends JpaRepository { 6 | FinancialSituationResultProjection findByApplicationNumber(String applicationNumber); 7 | } 8 | -------------------------------------------------------------------------------- /credit-agency/src/main/java/com/mploed/dddwithspring/creditagency/messaging/CreditAgencyChannels.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.creditagency.messaging; 2 | 3 | import org.springframework.cloud.stream.annotation.Input; 4 | import org.springframework.messaging.SubscribableChannel; 5 | 6 | public interface CreditAgencyChannels { 7 | String APPLICATION_SUBMITTED = "applicationSubmittedIn"; 8 | 9 | @Input 10 | SubscribableChannel applicationSubmittedIn(); 11 | } 12 | -------------------------------------------------------------------------------- /scoring/scoring-application/src/main/java/com/mploed/dddwithspring/scoring/ScoringApplication.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class ScoringApplication { 8 | public static void main(String[] args) { 9 | SpringApplication.run(ScoringApplication.class, args); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /credit-sales-funnel/src/main/java/com/mploed/dddwithspring/creditsalesfunnel/repository/FinancingRepository.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.creditsalesfunnel.repository; 2 | 3 | import com.mploed.dddwithspring.creditsalesfunnel.model.financing.Financing; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | public interface FinancingRepository extends JpaRepository { 7 | Financing findByApplicationNumber(String applicationNumber); 8 | } 9 | -------------------------------------------------------------------------------- /credit-sales-funnel/src/main/java/com/mploed/dddwithspring/creditsalesfunnel/repository/HouseholdRepository.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.creditsalesfunnel.repository; 2 | 3 | import com.mploed.dddwithspring.creditsalesfunnel.model.household.Household; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | public interface HouseholdRepository extends JpaRepository { 7 | Household findByApplicationNumber(String applicationNumber); 8 | } 9 | -------------------------------------------------------------------------------- /scoring/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:8-jdk-alpine 2 | LABEL maintainer="michael.ploed@innoq.com" 3 | VOLUME /tmp 4 | ENV JAVA_OPTS="" 5 | ENV SPRING_APPLICATION_JSON='{"creditAgencyFeed": "http://credit-agency:9002/person-rating/feed", "spring": {"rabbitmq": {"host": "localrabbit", "addresses": "rabbit-mq"}}}' 6 | ENTRYPOINT exec java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar 7 | EXPOSE 9001 8 | ADD scoring-application/target/scoring-application-0.0.1-SNAPSHOT.jar app.jar 9 | -------------------------------------------------------------------------------- /assets/.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 | -------------------------------------------------------------------------------- /scoring/adapters-input/src/main/java/com/mploed/dddwithspring/scoring/incoming/realEstate/Interior.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.incoming.realEstate; 2 | 3 | public enum Interior { 4 | STANDARD("Standard"), 5 | LUXURY("Luxury"), 6 | SIMPLE("Simple"); 7 | 8 | private final String displayName; 9 | 10 | Interior(String displayName) { 11 | this.displayName = displayName; 12 | } 13 | 14 | public String getDisplayName() { 15 | return displayName; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /scoring/aggregates/src/main/java/com/mploed/dddwithspring/scoring/financialSituation/Outgoings.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.financialSituation; 2 | 3 | import com.mploed.dddwithspring.scoring.Money; 4 | 5 | class Outgoings { 6 | Money rent; 7 | Money costOfLiving; 8 | 9 | Outgoings(Money rent, Money costOfLiving) { 10 | this.rent = rent; 11 | this.costOfLiving = costOfLiving; 12 | } 13 | 14 | Money sum() { 15 | return rent.add(costOfLiving); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /assets/src/test/java/com/mploed/dddwithspring/assets/AssetsApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.assets; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class AssetsApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /scoring/aggregates/src/main/java/com/mploed/dddwithspring/scoring/agencyResult/KoCriteria.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.agencyResult; 2 | 3 | class KoCriteria { 4 | private String key; 5 | private String messageText; 6 | 7 | KoCriteria(String key, String messageText) { 8 | this.key = key; 9 | this.messageText = messageText; 10 | } 11 | 12 | String getKey() { 13 | return key; 14 | } 15 | 16 | String getMessageText() { 17 | return messageText; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /scoring/aggregates/src/main/java/com/mploed/dddwithspring/scoring/financialSituation/Incomings.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.financialSituation; 2 | 3 | import com.mploed.dddwithspring.scoring.Money; 4 | 5 | class Incomings { 6 | Money salary; 7 | Money otherIncome; 8 | 9 | Incomings(Money salary, Money otherIncome) { 10 | this.salary = salary; 11 | this.otherIncome = otherIncome; 12 | } 13 | 14 | Money sum() { 15 | return salary.add(otherIncome); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /credit-sales-funnel/src/main/java/com/mploed/dddwithspring/creditsalesfunnel/model/realEstate/Interior.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.creditsalesfunnel.model.realEstate; 2 | 3 | public enum Interior { 4 | STANDARD("Standard"), 5 | LUXURY("Luxury"), 6 | SIMPLE("Simple"); 7 | 8 | private final String displayName; 9 | 10 | Interior(String displayName) { 11 | this.displayName = displayName; 12 | } 13 | 14 | public String getDisplayName() { 15 | return displayName; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /scoring/aggregates/src/main/java/com/mploed/dddwithspring/scoring/agencyResult/WarningMessage.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.agencyResult; 2 | 3 | class WarningMessage { 4 | private String key; 5 | private String messageText; 6 | 7 | WarningMessage(String key, String messageText) { 8 | this.key = key; 9 | this.messageText = messageText; 10 | } 11 | 12 | String getKey() { 13 | return key; 14 | } 15 | 16 | String getMessageText() { 17 | return messageText; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /scoring/adapters-input/src/main/java/com/mploed/dddwithspring/scoring/incoming/realEstate/ParkingSpace.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.incoming.realEstate; 2 | 3 | public enum ParkingSpace { 4 | NOT_PRESENT("Not present"), 5 | CARPORT("Carport"), 6 | GARAGE("Garage"); 7 | 8 | private final String displayName; 9 | 10 | ParkingSpace(String displayName) { 11 | this.displayName = displayName; 12 | } 13 | 14 | public String getDisplayName() { 15 | return displayName; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /scoring/adapters-input/src/main/java/com/mploed/dddwithspring/scoring/incoming/realEstate/Construction.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.incoming.realEstate; 2 | 3 | public enum Construction { 4 | PREFABRICATED_HOUSE("Prefabricated house"), 5 | WOOD("Wood"), 6 | STONE("Stone"); 7 | 8 | private final String displayName; 9 | 10 | Construction(String displayName) { 11 | this.displayName = displayName; 12 | } 13 | 14 | public String getDisplayName() { 15 | return displayName; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /scoring/adapters-input/src/main/java/com/mploed/dddwithspring/scoring/incoming/realEstate/TypeOfUse.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.incoming.realEstate; 2 | 3 | public enum TypeOfUse { 4 | FOR_LEASE("For lease"), 5 | SELF_OCCUPIED("Self occupied"), 6 | COMMERCIAL("Commercial"); 7 | 8 | private final String displayName; 9 | 10 | TypeOfUse(String displayName) { 11 | this.displayName = displayName; 12 | } 13 | 14 | public String getDisplayName() { 15 | return displayName; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /credit-sales-funnel/src/main/java/com/mploed/dddwithspring/creditsalesfunnel/model/realEstate/ParkingSpace.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.creditsalesfunnel.model.realEstate; 2 | 3 | public enum ParkingSpace { 4 | NOT_PRESENT("Not present"), 5 | CARPORT("Carport"), 6 | GARAGE("Garage"); 7 | 8 | private final String displayName; 9 | 10 | ParkingSpace(String displayName) { 11 | this.displayName = displayName; 12 | } 13 | 14 | public String getDisplayName() { 15 | return displayName; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /credit-sales-funnel/src/main/java/com/mploed/dddwithspring/creditsalesfunnel/repository/RealEstatePropertyRepository.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.creditsalesfunnel.repository; 2 | 3 | import com.mploed.dddwithspring.creditsalesfunnel.model.realEstate.RealEstateProperty; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | public interface RealEstatePropertyRepository extends JpaRepository { 7 | RealEstateProperty findByApplicationNumber(String applicationNumber); 8 | } 9 | -------------------------------------------------------------------------------- /scoring/adapters-input/src/main/java/com/mploed/dddwithspring/scoring/incoming/AgencyMessage.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.incoming; 2 | 3 | public class AgencyMessage { 4 | private String key; 5 | private String messageText; 6 | 7 | AgencyMessage(String key, String messageText) { 8 | this.key = key; 9 | this.messageText = messageText; 10 | } 11 | 12 | public String getKey() { 13 | return key; 14 | } 15 | 16 | public String getMessageText() { 17 | return messageText; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /scoring/application-services/src/main/java/com/mploed/dddwithspring/scoring/appservices/repositories/AgencyResultRepository.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.appservices.repositories; 2 | 3 | 4 | import com.mploed.dddwithspring.scoring.PersonId; 5 | import com.mploed.dddwithspring.scoring.agencyResult.AgencyResultAggregate; 6 | 7 | public interface AgencyResultRepository { 8 | void save(AgencyResultAggregate agencyResultAggregate); 9 | 10 | AgencyResultAggregate retrieve(PersonId personId); 11 | } 12 | -------------------------------------------------------------------------------- /credit-sales-funnel/src/main/java/com/mploed/dddwithspring/creditsalesfunnel/model/realEstate/Construction.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.creditsalesfunnel.model.realEstate; 2 | 3 | public enum Construction { 4 | PREFABRICATED_HOUSE("Prefabricated house"), 5 | WOOD("Wood"), 6 | STONE("Stone"); 7 | 8 | private final String displayName; 9 | 10 | Construction(String displayName) { 11 | this.displayName = displayName; 12 | } 13 | 14 | public String getDisplayName() { 15 | return displayName; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /credit-sales-funnel/src/main/java/com/mploed/dddwithspring/creditsalesfunnel/model/realEstate/TypeOfUse.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.creditsalesfunnel.model.realEstate; 2 | 3 | public enum TypeOfUse { 4 | FOR_LEASE("For lease"), 5 | SELF_OCCUPIED("Self occupied"), 6 | COMMERCIAL("Commercial"); 7 | 8 | private final String displayName; 9 | 10 | TypeOfUse(String displayName) { 11 | this.displayName = displayName; 12 | } 13 | 14 | public String getDisplayName() { 15 | return displayName; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /scoring/adapters-input/src/main/java/com/mploed/dddwithspring/scoring/incoming/realEstate/Attic.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.incoming.realEstate; 2 | 3 | public enum Attic { 4 | NOT_PRESENT("Not present"), 5 | PARTLY_DEVELOPED("Partly developed"), 6 | FULLY_DEVELOPED("Fully developed"); 7 | 8 | private final String displayName; 9 | 10 | Attic(String displayName) { 11 | this.displayName = displayName; 12 | } 13 | 14 | public String getDisplayName() { 15 | return displayName; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /scoring/adapters-input/src/main/java/com/mploed/dddwithspring/scoring/incoming/applicant/MaritalStatus.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.incoming.applicant; 2 | 3 | public enum MaritalStatus { 4 | SINGLE("Single"), 5 | MARRIED("Married"), 6 | DIVORCED("Divorced"), 7 | WIDOWED("Widowed"); 8 | 9 | private final String displayName; 10 | 11 | MaritalStatus(String displayName) { 12 | this.displayName = displayName; 13 | } 14 | 15 | public String getDisplayName() { 16 | return displayName; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /scoring/adapters-input/src/main/java/com/mploed/dddwithspring/scoring/incoming/realEstate/Basement.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.incoming.realEstate; 2 | 3 | public enum Basement { 4 | NOT_PRESENT("Not present"), 5 | PARTLY_DEVELOPED("Partly developed"), 6 | FULLY_DEVELOPED("Fully developed"); 7 | 8 | private final String displayName; 9 | 10 | Basement(String displayName) { 11 | this.displayName = displayName; 12 | } 13 | 14 | public String getDisplayName() { 15 | return displayName; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /credit-sales-funnel/src/main/java/com/mploed/dddwithspring/creditsalesfunnel/model/realEstate/Attic.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.creditsalesfunnel.model.realEstate; 2 | 3 | public enum Attic { 4 | NOT_PRESENT("Not present"), 5 | PARTLY_DEVELOPED("Partly developed"), 6 | FULLY_DEVELOPED("Fully developed"); 7 | 8 | private final String displayName; 9 | 10 | Attic(String displayName) { 11 | this.displayName = displayName; 12 | } 13 | 14 | public String getDisplayName() { 15 | return displayName; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /credit-sales-funnel/src/main/java/com/mploed/dddwithspring/creditsalesfunnel/model/applicant/MaritalStatus.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.creditsalesfunnel.model.applicant; 2 | 3 | public enum MaritalStatus { 4 | SINGLE("Single"), 5 | MARRIED("Married"), 6 | DIVORCED("Divorced"), 7 | WIDOWED("Widowed"); 8 | 9 | private final String displayName; 10 | 11 | MaritalStatus(String displayName) { 12 | this.displayName = displayName; 13 | } 14 | 15 | public String getDisplayName() { 16 | return displayName; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /credit-agency/src/main/java/com/mploed/dddwithspring/creditagency/events/incoming/applicant/MaritalStatus.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.creditagency.events.incoming.applicant; 2 | 3 | public enum MaritalStatus { 4 | SINGLE("Single"), 5 | MARRIED("Married"), 6 | DIVORCED("Divorced"), 7 | WIDOWED("Widowed"); 8 | 9 | private final String displayName; 10 | 11 | MaritalStatus(String displayName) { 12 | this.displayName = displayName; 13 | } 14 | 15 | public String getDisplayName() { 16 | return displayName; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /credit-sales-funnel/src/main/java/com/mploed/dddwithspring/creditsalesfunnel/model/realEstate/Basement.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.creditsalesfunnel.model.realEstate; 2 | 3 | public enum Basement { 4 | NOT_PRESENT("Not present"), 5 | PARTLY_DEVELOPED("Partly developed"), 6 | FULLY_DEVELOPED("Fully developed"); 7 | 8 | private final String displayName; 9 | 10 | Basement(String displayName) { 11 | this.displayName = displayName; 12 | } 13 | 14 | public String getDisplayName() { 15 | return displayName; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /scoring/adapters-input/src/main/java/com/mploed/dddwithspring/scoring/incoming/realEstate/UsageOfLoan.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.incoming.realEstate; 2 | 3 | public enum UsageOfLoan { 4 | PURCHASE("Purchase"), 5 | CONSTRUCTION("Construction"), 6 | MODERNIZATION("Modernization"), 7 | OTHER("Other"); 8 | 9 | private final String displayName; 10 | 11 | UsageOfLoan(String displayName) { 12 | this.displayName = displayName; 13 | } 14 | 15 | public String getDisplayName() { 16 | return displayName; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /credit-sales-funnel/src/main/java/com/mploed/dddwithspring/creditsalesfunnel/model/realEstate/UsageOfLoan.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.creditsalesfunnel.model.realEstate; 2 | 3 | public enum UsageOfLoan { 4 | PURCHASE("Purchase"), 5 | CONSTRUCTION("Construction"), 6 | MODERNIZATION("Modernization"), 7 | OTHER("Other"); 8 | 9 | private final String displayName; 10 | 11 | UsageOfLoan(String displayName) { 12 | this.displayName = displayName; 13 | } 14 | 15 | public String getDisplayName() { 16 | return displayName; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /scoring/application-services/src/main/java/com/mploed/dddwithspring/scoring/appservices/repositories/ScoringResultRepository.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.appservices.repositories; 2 | 3 | import com.mploed.dddwithspring.scoring.ApplicationNumber; 4 | import com.mploed.dddwithspring.scoring.scoringResult.ScoringResultAggregate; 5 | 6 | public interface ScoringResultRepository { 7 | void save(ScoringResultAggregate scoringResultAggregate); 8 | 9 | ScoringResultAggregate findByApplicationNumber(ApplicationNumber applicationNumber); 10 | } 11 | -------------------------------------------------------------------------------- /scoring/adapters-input/src/main/java/com/mploed/dddwithspring/scoring/incoming/realEstate/ObjectType.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.incoming.realEstate; 2 | 3 | public enum ObjectType { 4 | SEMI_DETACHED_HOUSE("Semi detached house"), 5 | ROW_HOUSE("Row house"), 6 | DETACHED_HOUSE("Detached house"), 7 | APARTMENT("Apartment"); 8 | 9 | private final String displayName; 10 | 11 | ObjectType(String displayName) { 12 | this.displayName = displayName; 13 | } 14 | 15 | public String getDisplayName() { 16 | return displayName; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /scoring/adapters-output/src/main/java/com/mploed/dddwithspring/scoring/applicant/ApplicantResultDAO.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.applicant; 2 | 3 | import com.mploed.dddwithspring.scoring.agencyResult.AgencyResultProjection; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | public interface ApplicantResultDAO extends JpaRepository { 7 | ApplicantResultProjection findByApplicationNumber(String applicationNumber); 8 | 9 | ApplicantResultProjection findByPersonId(String personId); 10 | 11 | } 12 | -------------------------------------------------------------------------------- /credit-sales-funnel/src/main/java/com/mploed/dddwithspring/creditsalesfunnel/model/realEstate/ObjectType.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.creditsalesfunnel.model.realEstate; 2 | 3 | public enum ObjectType { 4 | SEMI_DETACHED_HOUSE("Semi detached house"), 5 | ROW_HOUSE("Row house"), 6 | DETACHED_HOUSE("Detached house"), 7 | APARTMENT("Apartment"); 8 | 9 | private final String displayName; 10 | 11 | ObjectType(String displayName) { 12 | this.displayName = displayName; 13 | } 14 | 15 | public String getDisplayName() { 16 | return displayName; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /scoring/adapters-input/src/main/java/com/mploed/dddwithspring/scoring/incoming/realEstate/ApartmentLocation.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.incoming.realEstate; 2 | 3 | public enum ApartmentLocation { 4 | BASEMENT_FLOOR("Basement floor"), 5 | GROUND_FLOOR("Ground floor"), 6 | UPPER_FLOOR("Upper floor"), 7 | PENTHOUSE("Penthouse"); 8 | 9 | private final String displayName; 10 | 11 | ApartmentLocation(String displayName) { 12 | this.displayName = displayName; 13 | } 14 | 15 | public String getDisplayName() { 16 | return displayName; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /credit-sales-funnel/src/main/java/com/mploed/dddwithspring/creditsalesfunnel/model/realEstate/ApartmentLocation.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.creditsalesfunnel.model.realEstate; 2 | 3 | public enum ApartmentLocation { 4 | BASEMENT_FLOOR("Basement floor"), 5 | GROUND_FLOOR("Ground floor"), 6 | UPPER_FLOOR("Upper floor"), 7 | PENTHOUSE("Penthouse"); 8 | 9 | private final String displayName; 10 | 11 | ApartmentLocation(String displayName) { 12 | this.displayName = displayName; 13 | } 14 | 15 | public String getDisplayName() { 16 | return displayName; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /scoring/application-services/src/main/java/com/mploed/dddwithspring/scoring/appservices/repositories/FinancialSituationResultRepository.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.appservices.repositories; 2 | 3 | 4 | import com.mploed.dddwithspring.scoring.ApplicationNumber; 5 | import com.mploed.dddwithspring.scoring.financialSituation.FinancialSituationAggregate; 6 | 7 | public interface FinancialSituationResultRepository { 8 | void save(FinancialSituationAggregate financialSituationAggregate); 9 | 10 | FinancialSituationAggregate retrieve(ApplicationNumber applicationNumber); 11 | } 12 | -------------------------------------------------------------------------------- /scoring/adapters-input/src/main/java/com/mploed/dddwithspring/scoring/messaging/ApplicationProcessChannels.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.messaging; 2 | 3 | import org.springframework.cloud.stream.annotation.Input; 4 | import org.springframework.cloud.stream.annotation.Output; 5 | import org.springframework.messaging.MessageChannel; 6 | import org.springframework.messaging.SubscribableChannel; 7 | 8 | public interface ApplicationProcessChannels { 9 | String APPLICATION_SUBMITTED = "applicationSubmittedIn"; 10 | 11 | @Input 12 | SubscribableChannel applicationSubmittedIn(); 13 | } 14 | -------------------------------------------------------------------------------- /infrastructure_varnish/default.vcl: -------------------------------------------------------------------------------- 1 | vcl 4.0; 2 | 3 | 4 | backend default { 5 | .host = "credit-sales-funnel"; 6 | .port = "9000"; 7 | } 8 | 9 | backend scoring { 10 | .host = "scoring"; 11 | .port = "9001"; 12 | } 13 | 14 | sub vcl_recv { 15 | if (req.url ~ "^/scoring") { 16 | set req.backend_hint = scoring; 17 | } else if (req.url ~ "^/application") { 18 | set req.backend_hint = default; 19 | return(pass); 20 | } else { 21 | set req.backend_hint = default; 22 | } 23 | } 24 | 25 | sub vcl_backend_response { 26 | set beresp.do_esi = true; 27 | } -------------------------------------------------------------------------------- /scoring/adapters-input/src/main/java/com/mploed/dddwithspring/scoring/incoming/applicant/Employment.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.incoming.applicant; 2 | 3 | public enum Employment { 4 | EMPLOYEE("Employee"), OFFICIAL("Official"), 5 | PENSIONER("Pensioner"), 6 | STUDENT("Student"), 7 | TRAINEE("Trainee"), 8 | FREELANCER("Freelancer"), 9 | UNEMPLOYED("Unemployed"), 10 | OTHER("Other"); 11 | 12 | private final String displayName; 13 | 14 | Employment(String displayName) { 15 | this.displayName = displayName; 16 | } 17 | 18 | public String getDisplayName() { 19 | return displayName; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /credit-agency/src/main/java/com/mploed/dddwithspring/creditagency/repository/PersonRatingRepository.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.creditagency.repository; 2 | 3 | import com.mploed.dddwithspring.creditagency.model.PersonRating; 4 | import org.springframework.data.domain.Example; 5 | import org.springframework.data.jpa.repository.JpaRepository; 6 | import org.springframework.data.jpa.repository.Query; 7 | 8 | import java.util.Date; 9 | 10 | 11 | public interface PersonRatingRepository extends JpaRepository { 12 | @Query("SELECT max(pr.lastUpdated) FROM PersonRating pr") 13 | Date lastUpdate(); 14 | 15 | } 16 | -------------------------------------------------------------------------------- /credit-sales-funnel/src/main/java/com/mploed/dddwithspring/creditsalesfunnel/model/applicant/Employment.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.creditsalesfunnel.model.applicant; 2 | 3 | public enum Employment { 4 | EMPLOYEE("Employee"), OFFICIAL("Official"), 5 | PENSIONER("Pensioner"), 6 | STUDENT("Student"), 7 | TRAINEE("Trainee"), 8 | FREELANCER("Freelancer"), 9 | UNEMPLOYED("Unemployed"), 10 | OTHER("Other"); 11 | 12 | private final String displayName; 13 | 14 | Employment(String displayName) { 15 | this.displayName = displayName; 16 | } 17 | 18 | public String getDisplayName() { 19 | return displayName; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /scoring/aggregates/src/test/resources/com/mploed/dddwithspring/scoring/archunit/scoring.puml: -------------------------------------------------------------------------------- 1 | @startuml 2 | 3 | skinparam componentStyle uml2 4 | skinparam component { 5 | BorderColor #grey 6 | BackgroundColor #white 7 | } 8 | 9 | [AgencyResult] <<..scoring.agencyResult..>> 10 | [Applicant] <<..scoring.applicant..>> 11 | [FinancialSituation] <<..scoring.financialSituation..>> 12 | [ScoringResult] <<..scoring.scoringResult..>> 13 | [SharedKernel] <<..scoring>> 14 | 15 | [AgencyResult] --> [SharedKernel] 16 | [Applicant] --> [SharedKernel] 17 | [FinancialSituation] --> [SharedKernel] 18 | [ScoringResult] --> [SharedKernel] 19 | 20 | @enduml -------------------------------------------------------------------------------- /credit-agency/src/main/java/com/mploed/dddwithspring/creditagency/events/incoming/applicant/Employment.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.creditagency.events.incoming.applicant; 2 | 3 | public enum Employment { 4 | EMPLOYEE("Employee"), OFFICIAL("Official"), 5 | PENSIONER("Pensioner"), 6 | STUDENT("Student"), 7 | TRAINEE("Trainee"), 8 | FREELANCER("Freelancer"), 9 | UNEMPLOYED("Unemployed"), 10 | OTHER("Other"); 11 | 12 | private final String displayName; 13 | 14 | Employment(String displayName) { 15 | this.displayName = displayName; 16 | } 17 | 18 | public String getDisplayName() { 19 | return displayName; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /scoring/application-services/src/main/java/com/mploed/dddwithspring/scoring/appservices/repositories/ApplicantResultRepository.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.appservices.repositories; 2 | 3 | 4 | import com.mploed.dddwithspring.scoring.ApplicationNumber; 5 | import com.mploed.dddwithspring.scoring.PersonId; 6 | import com.mploed.dddwithspring.scoring.applicant.ApplicantAggregate; 7 | 8 | public interface ApplicantResultRepository { 9 | void save(ApplicantAggregate applicantAggregate); 10 | 11 | ApplicantAggregate retrieve(ApplicationNumber applicationNumber); 12 | 13 | ApplicantAggregate retrieve(PersonId personId); 14 | } 15 | -------------------------------------------------------------------------------- /scoring/adapters-input/src/main/java/com/mploed/dddwithspring/scoring/incoming/applicant/Business.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.incoming.applicant; 2 | 3 | public enum Business { 4 | BANKING("Banking"), 5 | ENERGY("Energy"), 6 | INSURANCE("Insurance"), 7 | CONSTRUCTION("Construction"), 8 | AGRICULTURE("Agriculture"), 9 | INDUSTRY("Industry"), 10 | PUBLIC_SERVICE("Public service"), 11 | OTHER("Other"); 12 | 13 | private final String displayName; 14 | 15 | Business(String displayName) { 16 | this.displayName = displayName; 17 | } 18 | 19 | public String getDisplayName() { 20 | return displayName; 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /credit-sales-funnel/src/main/java/com/mploed/dddwithspring/creditsalesfunnel/model/applicant/Business.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.creditsalesfunnel.model.applicant; 2 | 3 | public enum Business { 4 | BANKING("Banking"), 5 | ENERGY("Energy"), 6 | INSURANCE("Insurance"), 7 | CONSTRUCTION("Construction"), 8 | AGRICULTURE("Agriculture"), 9 | INDUSTRY("Industry"), 10 | PUBLIC_SERVICE("Public service"), 11 | OTHER("Other"); 12 | 13 | private final String displayName; 14 | 15 | Business(String displayName) { 16 | this.displayName = displayName; 17 | } 18 | 19 | public String getDisplayName() { 20 | return displayName; 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /credit-agency/src/main/java/com/mploed/dddwithspring/creditagency/CreditAgencyApplication.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.creditagency; 2 | 3 | import com.mploed.dddwithspring.creditagency.messaging.CreditAgencyChannels; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | import org.springframework.cloud.stream.annotation.EnableBinding; 7 | 8 | @SpringBootApplication 9 | @EnableBinding(CreditAgencyChannels.class) 10 | public class CreditAgencyApplication { 11 | public static void main(String[] args) { 12 | SpringApplication.run(CreditAgencyApplication.class); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /credit-agency/src/main/java/com/mploed/dddwithspring/creditagency/events/incoming/applicant/Business.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.creditagency.events.incoming.applicant; 2 | 3 | public enum Business { 4 | BANKING("Banking"), 5 | ENERGY("Energy"), 6 | INSURANCE("Insurance"), 7 | CONSTRUCTION("Construction"), 8 | AGRICULTURE("Agriculture"), 9 | INDUSTRY("Industry"), 10 | PUBLIC_SERVICE("Public service"), 11 | OTHER("Other"); 12 | 13 | private final String displayName; 14 | 15 | Business(String displayName) { 16 | this.displayName = displayName; 17 | } 18 | 19 | public String getDisplayName() { 20 | return displayName; 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /credit-sales-funnel/src/main/java/com/mploed/dddwithspring/creditsalesfunnel/repository/ApplicantRepository.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.creditsalesfunnel.repository; 2 | 3 | import com.mploed.dddwithspring.creditsalesfunnel.model.applicant.Applicant; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | import java.util.List; 7 | 8 | public interface ApplicantRepository extends JpaRepository { 9 | public Applicant findByApplicationNumberAndApplicantNumber(String applicationNumber, String applicantNumber); 10 | 11 | public List findByApplicationNumberOrderByApplicantNumber(String applicationNumber); 12 | } 13 | -------------------------------------------------------------------------------- /scoring/adapters-input/src/main/java/com/mploed/dddwithspring/scoring/incoming/realEstate/Feature.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.incoming.realEstate; 2 | 3 | public enum Feature { 4 | SOLAR_COLLECTORS("Solar collectors"), 5 | PHOTOVOLTAICS("Photovoltaics"), 6 | SPA("Spa"), 7 | TWO_OR_MORE_BATHS("Two or more baths"), 8 | EV_CHARGER("Charger for electric vehicle"), 9 | POOL("Pool"), 10 | SUMMERHOUSE_IN_GARDEN("Summerhouse in the garden"), 11 | SAT_TV("Satellite TV"); 12 | 13 | private final String displayName; 14 | 15 | Feature(String displayName) { 16 | this.displayName = displayName; 17 | } 18 | 19 | public String getDisplayName() { 20 | return displayName; 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /scoring/aggregates/src/main/java/com/mploed/dddwithspring/scoring/applicant/AccountBalance.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.applicant; 2 | 3 | import com.mploed.dddwithspring.scoring.Money; 4 | 5 | import java.math.BigDecimal; 6 | 7 | class AccountBalance { 8 | private Money balance; 9 | 10 | AccountBalance(BigDecimal balance) { 11 | this(new Money(balance)); 12 | } 13 | AccountBalance(Money balance) { 14 | this.balance = balance; 15 | } 16 | 17 | int calculateScoringPoints() { 18 | if(balance.isGreaterThan(new Money(3000))) { 19 | return 10; 20 | } else { 21 | return 0; 22 | } 23 | } 24 | 25 | BigDecimal toBigDecimal() { 26 | return balance.getAmount(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /scoring/application-services/src/main/java/com/mploed/dddwithspring/scoring/appservices/internalevents/CreditAgencyResultArrived.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.appservices.internalevents; 2 | 3 | import com.mploed.dddwithspring.scoring.ApplicationNumber; 4 | import com.mploed.dddwithspring.scoring.PersonId; 5 | import org.springframework.context.ApplicationEvent; 6 | 7 | public class CreditAgencyResultArrived extends ApplicationEvent { 8 | private PersonId personId; 9 | 10 | public CreditAgencyResultArrived(Object source, String personId) { 11 | super(source); 12 | this.personId = new PersonId(personId); 13 | } 14 | 15 | public PersonId getPersonId() { 16 | return personId; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /credit-sales-funnel/src/main/java/com/mploed/dddwithspring/creditsalesfunnel/model/realEstate/Feature.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.creditsalesfunnel.model.realEstate; 2 | 3 | public enum Feature { 4 | SOLAR_COLLECTORS("Solar collectors"), 5 | PHOTOVOLTAICS("Photovoltaics"), 6 | SPA("Spa"), 7 | TWO_OR_MORE_BATHS("Two or more baths"), 8 | EV_CHARGER("Charger for electric vehicle"), 9 | POOL("Pool"), 10 | SUMMERHOUSE_IN_GARDEN("Summerhouse in the garden"), 11 | SAT_TV("Satellite TV"); 12 | 13 | private final String displayName; 14 | 15 | Feature(String displayName) { 16 | this.displayName = displayName; 17 | } 18 | 19 | public String getDisplayName() { 20 | return displayName; 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /credit-sales-funnel/src/main/java/com/mploed/dddwithspring/creditsalesfunnel/CreditSalesFunnelApplication.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.creditsalesfunnel; 2 | 3 | import com.mploed.dddwithspring.creditsalesfunnel.event.CreditSalesFunnelChannels; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | import org.springframework.cloud.stream.annotation.EnableBinding; 7 | 8 | @SpringBootApplication 9 | @EnableBinding(CreditSalesFunnelChannels.class) 10 | public class CreditSalesFunnelApplication { 11 | 12 | public static void main(String[] args) { 13 | SpringApplication.run(CreditSalesFunnelApplication.class, args); 14 | } 15 | 16 | 17 | } 18 | -------------------------------------------------------------------------------- /infrastructure_varnish/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:14.04 2 | RUN apt-get update && apt-get dist-upgrade -y -qq 3 | RUN apt-get install -y -qq apt-transport-https 4 | RUN apt-get install -y -qq curl && \ 5 | curl -L https://packagecloud.io/varnishcache/varnish41/gpgkey | sudo apt-key add - && \ 6 | echo "deb https://packagecloud.io/varnishcache/varnish41/ubuntu/ trusty main" \ 7 | >> /etc/apt/sources.list.d/varnishcache_varnish41.list && \ 8 | echo "deb-src https://packagecloud.io/varnishcache/varnish41/ubuntu/ trusty main" \ 9 | >> /etc/apt/sources.list.d/varnishcache_varnish41.list 10 | RUN apt-get update 11 | RUN apt-get install -y -qq varnish 12 | COPY default.vcl /etc/varnish/default.vcl 13 | COPY start /start 14 | RUN chmod 0755 /start 15 | CMD ["/start"] -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.mploed.dddwithspring 6 | parent 7 | 0.0.1-SNAPSHOT 8 | 9 | assets 10 | credit-sales-funnel 11 | scoring 12 | credit-agency 13 | 14 | pom 15 | 16 | ddd-with-spring 17 | Domain-driven Design with Spring 18 | 19 | 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.ear 17 | *.zip 18 | *.tar.gz 19 | *.rar 20 | 21 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 22 | hs_err_pid* 23 | 24 | target/ 25 | !.mvn/wrapper/maven-wrapper.jar 26 | 27 | ### STS ### 28 | .apt_generated 29 | .classpath 30 | .factorypath 31 | .project 32 | .settings 33 | .springBeans 34 | .sts4-cache 35 | 36 | ### IntelliJ IDEA ### 37 | .idea 38 | *.iws 39 | *.iml 40 | *.ipr 41 | 42 | ### NetBeans ### 43 | nbproject/private/ 44 | build/ 45 | nbbuild/ 46 | dist/ 47 | nbdist/ 48 | .nb-gradle/ -------------------------------------------------------------------------------- /scoring/adapters-output/src/main/java/com/mploed/dddwithspring/scoring/agencyResult/AgencyMessage.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.agencyResult; 2 | 3 | import javax.persistence.Embeddable; 4 | 5 | @Embeddable 6 | public class AgencyMessage { 7 | private String key; 8 | private String message; 9 | 10 | public AgencyMessage() { 11 | } 12 | 13 | AgencyMessage(String key, String message) { 14 | this.key = key; 15 | this.message = message; 16 | } 17 | 18 | public String getKey() { 19 | return key; 20 | } 21 | 22 | public void setKey(String key) { 23 | this.key = key; 24 | } 25 | 26 | public String getMessage() { 27 | return message; 28 | } 29 | 30 | public void setMessage(String message) { 31 | this.message = message; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /scoring/microarchitecture/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.mploed.dddwithspring.scoring 8 | microarchitecture 9 | 0.0.1-SNAPSHOT 10 | 11 | 12 | UTF-8 13 | 1.8 14 | 1.8 15 | 16 | 17 | -------------------------------------------------------------------------------- /scoring/aggregates/src/main/java/com/mploed/dddwithspring/scoring/financialSituation/FinancialSituationRootEntity.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.financialSituation; 2 | 3 | 4 | import com.mploed.dddwithspring.scoring.ApplicationNumber; 5 | import com.mploed.dddwithspring.scoring.Money; 6 | 7 | class FinancialSituationRootEntity { 8 | final ApplicationNumber applicationNumber; 9 | 10 | final Incomings incomings; 11 | final Outgoings outgoings; 12 | 13 | FinancialSituationRootEntity(ApplicationNumber applicationNumber, Incomings incomings, Outgoings outgoings) { 14 | this.applicationNumber = applicationNumber; 15 | this.incomings = incomings; 16 | this.outgoings = outgoings; 17 | } 18 | 19 | Money sum() { 20 | return incomings.sum().add(outgoings.sum()); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /scoring/application-services/src/main/java/com/mploed/dddwithspring/scoring/appservices/internalevents/CreditApplicationArrived.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.appservices.internalevents; 2 | 3 | import com.mploed.dddwithspring.scoring.ApplicationNumber; 4 | import com.mploed.dddwithspring.scoring.PersonId; 5 | import org.springframework.context.ApplicationEvent; 6 | 7 | public class CreditApplicationArrived extends ApplicationEvent { 8 | private ApplicationNumber applicationNumber; 9 | 10 | public CreditApplicationArrived(Object source, String applicationNumber) { 11 | super(source); 12 | this.applicationNumber = new ApplicationNumber(applicationNumber); 13 | } 14 | 15 | 16 | public ApplicationNumber getApplicationNumber() { 17 | return applicationNumber; 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /scoring/sharedmodel/src/test/java/com/mploed/dddwithspring/scoring/MoneyTest.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring; 2 | 3 | 4 | import org.junit.Test; 5 | 6 | import java.math.BigDecimal; 7 | 8 | import static org.junit.Assert.assertEquals; 9 | import static org.junit.Assert.assertFalse; 10 | import static org.junit.Assert.assertTrue; 11 | 12 | public class MoneyTest { 13 | 14 | @Test 15 | public void testIsGreaterThan() { 16 | Money base = new Money(8000); 17 | assertTrue(base.isGreaterThan(new Money(7000))); 18 | assertFalse(base.isGreaterThan(new Money(8000))); 19 | } 20 | 21 | @Test 22 | public void testAdd() { 23 | Money base = new Money(); 24 | assertEquals(BigDecimal.ZERO, base.getAmount()); 25 | Money moneyToAdd = new Money(100); 26 | assertEquals(new Money(100), base.add(moneyToAdd)); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /scoring/aggregates/src/main/java/com/mploed/dddwithspring/scoring/applicant/Address.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.applicant; 2 | 3 | class Address { 4 | private String city; 5 | private String postCode; 6 | private String street; 7 | 8 | Address(String street, String postCode, String city) { 9 | this.city = city; 10 | this.postCode = postCode; 11 | this.street = street; 12 | } 13 | 14 | int calculateScoringPoints() { 15 | if("Munich".equals(city)) { 16 | return 5; 17 | } else if ("Dortmund".equals(city)) { 18 | return -2; 19 | } else if ("Nürnberg".equals(city)) { 20 | return 8; 21 | }else { 22 | return 0; 23 | } 24 | } 25 | 26 | String getCity() { 27 | return city; 28 | } 29 | 30 | String getPostCode() { 31 | return postCode; 32 | } 33 | 34 | String getStreet() { 35 | return street; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /credit-sales-funnel/src/main/resources/templates/index.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 |
8 | 9 |
10 |

Get your big fat pug loan here

11 | 12 | 13 | 14 |
15 | 16 | 17 |
18 |
19 |
20 |

21 | Launch Scoring Activity Monitor 22 |

23 |
24 | 25 |
26 | 27 | -------------------------------------------------------------------------------- /credit-agency/src/main/java/com/mploed/dddwithspring/creditagency/events/incoming/ApplicationSubmittedEvent.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.creditagency.events.incoming; 2 | 3 | import com.mploed.dddwithspring.creditagency.events.incoming.applicant.Applicant; 4 | 5 | import java.util.Date; 6 | 7 | public class ApplicationSubmittedEvent { 8 | private String applicationNumber; 9 | private Applicant firstApplicant; 10 | 11 | public ApplicationSubmittedEvent() { 12 | } 13 | 14 | public String getApplicationNumber() { 15 | return applicationNumber; 16 | } 17 | 18 | public void setApplicationNumber(String applicationNumber) { 19 | this.applicationNumber = applicationNumber; 20 | } 21 | 22 | public Applicant getFirstApplicant() { 23 | return firstApplicant; 24 | } 25 | 26 | public void setFirstApplicant(Applicant firstApplicant) { 27 | this.firstApplicant = firstApplicant; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /scoring/application-services/src/main/java/com/mploed/dddwithspring/scoring/appservices/dto/FinancialSituation.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.appservices.dto; 2 | 3 | import com.mploed.dddwithspring.scoring.Money; 4 | 5 | public class FinancialSituation { 6 | private Money costOfLiving; 7 | private Money furtherIncome; 8 | private Money rent; 9 | private Money salary; 10 | 11 | public FinancialSituation(Money costOfLiving, Money furtherIncome, Money rent, Money salary) { 12 | this.costOfLiving = costOfLiving; 13 | this.furtherIncome = furtherIncome; 14 | this.rent = rent; 15 | this.salary = salary; 16 | } 17 | 18 | public Money getCostOfLiving() { 19 | return costOfLiving; 20 | } 21 | 22 | public Money getFurtherIncome() { 23 | return furtherIncome; 24 | } 25 | 26 | public Money getRent() { 27 | return rent; 28 | } 29 | 30 | public Money getSalary() { 31 | return salary; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /scoring/aggregates/src/main/java/com/mploed/dddwithspring/scoring/scoringResult/ScoringResultRootEntity.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.scoringResult; 2 | 3 | 4 | import com.mploed.dddwithspring.scoring.ApplicationNumber; 5 | 6 | class ScoringResultRootEntity { 7 | final ApplicationNumber applicationNumber; 8 | final OverallScoringResult overallScoringResult; 9 | final ScoringCalculationResults scoringCalculationResults; 10 | ScoringResultRootEntity(ApplicationNumber applicationNumber, int applicantScoringResult, int financialSituationScoringResult, int agencyScoringResult, boolean noGoCriteriaPresent) { 11 | this.applicationNumber = applicationNumber; 12 | this.scoringCalculationResults = new ScoringCalculationResults(applicantScoringResult, financialSituationScoringResult, agencyScoringResult, noGoCriteriaPresent); 13 | this.overallScoringResult = this.scoringCalculationResults.calculateOverallResult(); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /scoring/application-services/src/main/java/com/mploed/dddwithspring/scoring/appservices/dto/Applicant.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.appservices.dto; 2 | 3 | public class Applicant { 4 | private String firstName; 5 | private String lastName; 6 | private String street; 7 | private String postCode; 8 | private String city; 9 | 10 | public Applicant(String firstName, String lastName, String street, String postCode, String city) { 11 | this.firstName = firstName; 12 | this.lastName = lastName; 13 | this.street = street; 14 | this.postCode = postCode; 15 | this.city = city; 16 | } 17 | 18 | public String getFirstName() { 19 | return firstName; 20 | } 21 | 22 | public String getLastName() { 23 | return lastName; 24 | } 25 | 26 | public String getStreet() { 27 | return street; 28 | } 29 | 30 | public String getPostCode() { 31 | return postCode; 32 | } 33 | 34 | public String getCity() { 35 | return city; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /scoring/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | parent 7 | com.mploed.dddwithspring 8 | 0.0.1-SNAPSHOT 9 | 10 | pom 11 | 4.0.0 12 | 13 | scoring 14 | 0.0.1-SNAPSHOT 15 | 16 | 17 | microarchitecture 18 | sharedmodel 19 | aggregates 20 | 21 | adapters-input 22 | adapters-output 23 | scoring-application 24 | application-services 25 | 26 | 27 | -------------------------------------------------------------------------------- /scoring/sharedmodel/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.mploed.dddwithspring.scoring 8 | 0.0.1-SNAPSHOT 9 | sharedmodel 10 | jar 11 | 12 | 13 | 14 | UTF-8 15 | 1.8 16 | 1.8 17 | 18 | 19 | 20 | 21 | junit 22 | junit 23 | 4.13.1 24 | 25 | 26 | -------------------------------------------------------------------------------- /scoring/adapters-input/src/main/java/com/mploed/dddwithspring/scoring/incoming/applicant/Address.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.incoming.applicant; 2 | 3 | import java.io.Serializable; 4 | 5 | public class Address implements Serializable { 6 | private String street; 7 | 8 | private String postCode; 9 | 10 | private String city; 11 | 12 | public String getStreet() { 13 | return street; 14 | } 15 | 16 | public String getPostCode() { 17 | return postCode; 18 | } 19 | 20 | public String getCity() { 21 | return city; 22 | } 23 | 24 | public void setStreet(String street) { 25 | this.street = street; 26 | } 27 | 28 | public void setPostCode(String postCode) { 29 | this.postCode = postCode; 30 | } 31 | 32 | public void setCity(String city) { 33 | this.city = city; 34 | } 35 | 36 | @Override 37 | public String toString() { 38 | return "Address{" + 39 | "street='" + street + '\'' + 40 | ", postCode='" + postCode + '\'' + 41 | ", city='" + city + '\'' + 42 | '}'; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /credit-agency/src/main/java/com/mploed/dddwithspring/creditagency/events/incoming/applicant/Address.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.creditagency.events.incoming.applicant; 2 | 3 | import java.io.Serializable; 4 | 5 | public class Address implements Serializable { 6 | private String street; 7 | 8 | private String postCode; 9 | 10 | private String city; 11 | 12 | public String getStreet() { 13 | return street; 14 | } 15 | 16 | public String getPostCode() { 17 | return postCode; 18 | } 19 | 20 | public String getCity() { 21 | return city; 22 | } 23 | 24 | public void setStreet(String street) { 25 | this.street = street; 26 | } 27 | 28 | public void setPostCode(String postCode) { 29 | this.postCode = postCode; 30 | } 31 | 32 | public void setCity(String city) { 33 | this.city = city; 34 | } 35 | 36 | @Override 37 | public String toString() { 38 | return "Address{" + 39 | "street='" + street + '\'' + 40 | ", postCode='" + postCode + '\'' + 41 | ", city='" + city + '\'' + 42 | '}'; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /scoring/adapters-input/src/main/java/com/mploed/dddwithspring/scoring/WebSocketConfig.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | import org.springframework.messaging.simp.config.MessageBrokerRegistry; 5 | import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; 6 | import org.springframework.web.socket.config.annotation.StompEndpointRegistry; 7 | import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer; 8 | 9 | @Configuration 10 | @EnableWebSocketMessageBroker 11 | public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { 12 | 13 | @Override 14 | public void configureMessageBroker(MessageBrokerRegistry config) { 15 | config.enableSimpleBroker("/topic"); 16 | config.setApplicationDestinationPrefixes("/app"); 17 | } 18 | 19 | @Override 20 | public void registerStompEndpoints(StompEndpointRegistry registry) { 21 | registry.addEndpoint("/gs-guide-websocket").withSockJS(); 22 | } 23 | 24 | } -------------------------------------------------------------------------------- /scoring/adapters-input/src/main/java/com/mploed/dddwithspring/scoring/messaging/SpringEventListener.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.messaging; 2 | 3 | import com.mploed.dddwithspring.scoring.ApplicationNumber; 4 | import com.mploed.dddwithspring.scoring.appservices.ScoringApplicationService; 5 | import com.mploed.dddwithspring.scoring.appservices.internalevents.PartOfScoringPerformed; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.context.ApplicationListener; 8 | import org.springframework.stereotype.Component; 9 | 10 | @Component 11 | public class SpringEventListener implements ApplicationListener { 12 | 13 | private ScoringApplicationService scoringApplicationService; 14 | 15 | @Autowired 16 | public SpringEventListener(ScoringApplicationService scoringApplicationService) { 17 | this.scoringApplicationService = scoringApplicationService; 18 | } 19 | 20 | @Override 21 | public void onApplicationEvent(PartOfScoringPerformed event) { 22 | scoringApplicationService.performFinalScoring(event.getApplicationNumber()); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /scoring/adapters-input/src/main/java/com/mploed/dddwithspring/scoring/incoming/realEstate/ApartmentInformation.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.incoming.realEstate; 2 | 3 | import java.io.Serializable; 4 | 5 | public class ApartmentInformation implements Serializable { 6 | private int numberOfApartmentsInHouse; 7 | 8 | private String nameOfApartment; 9 | 10 | private ApartmentLocation apartmentLocation; 11 | 12 | public int getNumberOfApartmentsInHouse() { 13 | return numberOfApartmentsInHouse; 14 | } 15 | 16 | public void setNumberOfApartmentsInHouse(int numberOfApartmentsInHouse) { 17 | this.numberOfApartmentsInHouse = numberOfApartmentsInHouse; 18 | } 19 | 20 | public String getNameOfApartment() { 21 | return nameOfApartment; 22 | } 23 | 24 | public void setNameOfApartment(String nameOfApartment) { 25 | this.nameOfApartment = nameOfApartment; 26 | } 27 | 28 | public ApartmentLocation getApartmentLocation() { 29 | return apartmentLocation; 30 | } 31 | 32 | public void setApartmentLocation(ApartmentLocation apartmentLocation) { 33 | this.apartmentLocation = apartmentLocation; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /scoring/adapters-input/src/main/java/com/mploed/dddwithspring/scoring/incoming/financing/OwnResources.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.incoming.financing; 2 | 3 | import javax.persistence.Embeddable; 4 | import java.io.Serializable; 5 | 6 | public class OwnResources implements Serializable { 7 | private int liquidAssets; 8 | private int balanceFromBuildingSociety; 9 | private int ownManpower; 10 | 11 | public int sum() { 12 | return liquidAssets + balanceFromBuildingSociety + ownManpower; 13 | } 14 | 15 | public int getLiquidAssets() { 16 | return liquidAssets; 17 | } 18 | 19 | public void setLiquidAssets(int liquidAssets) { 20 | this.liquidAssets = liquidAssets; 21 | } 22 | 23 | public int getBalanceFromBuildingSociety() { 24 | return balanceFromBuildingSociety; 25 | } 26 | 27 | public void setBalanceFromBuildingSociety(int balanceFromBuildingSociety) { 28 | this.balanceFromBuildingSociety = balanceFromBuildingSociety; 29 | } 30 | 31 | public int getOwnManpower() { 32 | return ownManpower; 33 | } 34 | 35 | public void setOwnManpower(int ownManpower) { 36 | this.ownManpower = ownManpower; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /credit-sales-funnel/src/main/java/com/mploed/dddwithspring/creditsalesfunnel/model/financing/OwnResources.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.creditsalesfunnel.model.financing; 2 | 3 | import javax.persistence.Embeddable; 4 | import java.io.Serializable; 5 | 6 | @Embeddable 7 | public class OwnResources implements Serializable { 8 | private int liquidAssets; 9 | private int balanceFromBuildingSociety; 10 | private int ownManpower; 11 | 12 | public int sum() { 13 | return liquidAssets + balanceFromBuildingSociety + ownManpower; 14 | } 15 | 16 | public int getLiquidAssets() { 17 | return liquidAssets; 18 | } 19 | 20 | public void setLiquidAssets(int liquidAssets) { 21 | this.liquidAssets = liquidAssets; 22 | } 23 | 24 | public int getBalanceFromBuildingSociety() { 25 | return balanceFromBuildingSociety; 26 | } 27 | 28 | public void setBalanceFromBuildingSociety(int balanceFromBuildingSociety) { 29 | this.balanceFromBuildingSociety = balanceFromBuildingSociety; 30 | } 31 | 32 | public int getOwnManpower() { 33 | return ownManpower; 34 | } 35 | 36 | public void setOwnManpower(int ownManpower) { 37 | this.ownManpower = ownManpower; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /credit-agency/src/main/java/com/mploed/dddwithspring/creditagency/web/PersonRatingRestController.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.creditagency.web; 2 | 3 | import com.mploed.dddwithspring.creditagency.model.PersonRating; 4 | import com.mploed.dddwithspring.creditagency.repository.PersonRatingRepository; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.ui.Model; 7 | import org.springframework.web.bind.annotation.GetMapping; 8 | import org.springframework.web.bind.annotation.PathVariable; 9 | import org.springframework.web.bind.annotation.RequestMapping; 10 | import org.springframework.web.bind.annotation.RestController; 11 | 12 | @RestController 13 | @RequestMapping("rating/rest") 14 | public class PersonRatingRestController { 15 | private PersonRatingRepository personRatingRepository; 16 | 17 | @Autowired 18 | public PersonRatingRestController(PersonRatingRepository personRatingRepository) { 19 | this.personRatingRepository = personRatingRepository; 20 | } 21 | 22 | @GetMapping("/{ratingId}") 23 | public PersonRating index(Model model, @PathVariable Long ratingId) { 24 | return personRatingRepository.findById(ratingId).get(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /scoring/adapters-input/src/main/resources/static/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Big Pug Loans - Scoring monitor 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 20 |
21 |

Scoring activity

22 |
23 |
24 | 25 | 26 | 27 |
28 |
29 |
30 |
31 | 32 | -------------------------------------------------------------------------------- /scoring/adapters-output/src/main/java/com/mploed/dddwithspring/scoring/scoringResult/DetailedScoringResults.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.scoringResult; 2 | 3 | import javax.persistence.Embeddable; 4 | 5 | @Embeddable 6 | public class DetailedScoringResults { 7 | private int applicantScoringResult; 8 | private int financialSituationScoringResult; 9 | private int agencyScoringResult; 10 | private boolean noGoCriteriaPresent; 11 | 12 | public DetailedScoringResults(ScoringCalculationResults scoringCalculationResults) { 13 | this.applicantScoringResult = scoringCalculationResults.applicantScoringResult; 14 | this.financialSituationScoringResult = scoringCalculationResults.financialSituationScoringResult; 15 | this.agencyScoringResult = scoringCalculationResults.agencyScoringResult; 16 | this.noGoCriteriaPresent = scoringCalculationResults.noGoCriteriaPresent; 17 | } 18 | 19 | private DetailedScoringResults() { 20 | } 21 | 22 | public int getApplicantScoringResult() { 23 | return applicantScoringResult; 24 | } 25 | 26 | public int getFinancialSituationScoringResult() { 27 | return financialSituationScoringResult; 28 | } 29 | 30 | public int getAgencyScoringResult() { 31 | return agencyScoringResult; 32 | } 33 | 34 | public boolean isNoGoCriteriaPresent() { 35 | return noGoCriteriaPresent; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /scoring/adapters-output/src/main/java/com/mploed/dddwithspring/scoring/scoringResult/ScoringResultEntity.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.scoringResult; 2 | 3 | import javax.persistence.*; 4 | 5 | @Entity 6 | @Table(name = "SCORING_RESULT") 7 | public class ScoringResultEntity { 8 | @Id 9 | @GeneratedValue 10 | private Long id; 11 | 12 | private String applicationNumber; 13 | 14 | private int scorePoints; 15 | 16 | private String scoreColor; 17 | 18 | @Embedded 19 | private DetailedScoringResults detailedScoringResults; 20 | 21 | public ScoringResultEntity(String applicationNumber, int scorePoints, String scoreColor, DetailedScoringResults detailedScoringResults) { 22 | this.applicationNumber = applicationNumber; 23 | this.scorePoints = scorePoints; 24 | this.scoreColor = scoreColor; 25 | this.detailedScoringResults = detailedScoringResults; 26 | } 27 | 28 | private ScoringResultEntity() { 29 | } 30 | 31 | public Long getId() { 32 | return id; 33 | } 34 | 35 | public int getScorePoints() { 36 | return scorePoints; 37 | } 38 | 39 | public String getScoreColor() { 40 | return scoreColor; 41 | } 42 | 43 | public String getApplicationNumber() { 44 | return applicationNumber; 45 | } 46 | 47 | public DetailedScoringResults getDetailedScoringResults() { 48 | return detailedScoringResults; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /scoring/adapters-input/src/main/java/com/mploed/dddwithspring/scoring/InputAdaptersConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring; 2 | 3 | import com.mploed.dddwithspring.scoring.messaging.ApplicationProcessChannels; 4 | import org.springframework.cloud.stream.annotation.EnableBinding; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.context.event.ApplicationEventMulticaster; 8 | import org.springframework.context.event.SimpleApplicationEventMulticaster; 9 | import org.springframework.core.task.SimpleAsyncTaskExecutor; 10 | import org.springframework.scheduling.annotation.EnableScheduling; 11 | import org.springframework.web.client.RestTemplate; 12 | 13 | @Configuration 14 | @EnableBinding(ApplicationProcessChannels.class) 15 | @EnableScheduling 16 | public class InputAdaptersConfiguration { 17 | @Bean 18 | public RestTemplate restTemplate() { 19 | return new RestTemplate(); 20 | } 21 | 22 | @Bean(name = "applicationEventMulticaster") 23 | public ApplicationEventMulticaster simpleApplicationEventMulticaster() { 24 | SimpleApplicationEventMulticaster eventMulticaster 25 | = new SimpleApplicationEventMulticaster(); 26 | 27 | eventMulticaster.setTaskExecutor(new SimpleAsyncTaskExecutor()); 28 | return eventMulticaster; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /scoring/adapters-input/src/main/java/com/mploed/dddwithspring/scoring/incoming/financing/PurchaseCosts.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.incoming.financing; 2 | 3 | import javax.persistence.Embeddable; 4 | import java.io.Serializable; 5 | 6 | public class PurchaseCosts implements Serializable { 7 | private int priceOfLand; 8 | private int purchasePrice; 9 | private int reconstructionCosts; 10 | private int additionalPurchaseCharges; 11 | 12 | public int sum() { 13 | return priceOfLand + purchasePrice + reconstructionCosts + additionalPurchaseCharges; 14 | } 15 | public int getPriceOfLand() { 16 | return priceOfLand; 17 | } 18 | 19 | public void setPriceOfLand(int priceOfLand) { 20 | this.priceOfLand = priceOfLand; 21 | } 22 | 23 | public int getPurchasePrice() { 24 | return purchasePrice; 25 | } 26 | 27 | public void setPurchasePrice(int purchasePrice) { 28 | this.purchasePrice = purchasePrice; 29 | } 30 | 31 | public int getReconstructionCosts() { 32 | return reconstructionCosts; 33 | } 34 | 35 | public void setReconstructionCosts(int reconstructionCosts) { 36 | this.reconstructionCosts = reconstructionCosts; 37 | } 38 | 39 | public int getAdditionalPurchaseCharges() { 40 | return additionalPurchaseCharges; 41 | } 42 | 43 | public void setAdditionalPurchaseCharges(int additionalPurchaseCharges) { 44 | this.additionalPurchaseCharges = additionalPurchaseCharges; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /scoring/application-services/src/main/java/com/mploed/dddwithspring/scoring/appservices/internalevents/PartOfScoringPerformed.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.appservices.internalevents; 2 | 3 | import com.mploed.dddwithspring.scoring.ApplicationNumber; 4 | import com.mploed.dddwithspring.scoring.PersonId; 5 | import org.springframework.context.ApplicationEvent; 6 | 7 | public class PartOfScoringPerformed extends ApplicationEvent { 8 | private ApplicationNumber applicationNumber; 9 | private PersonId personId; 10 | private String cluster; 11 | 12 | public PartOfScoringPerformed(Object source, String cluster, String applicationNumber, PersonId personId) { 13 | super(source); 14 | this.applicationNumber = new ApplicationNumber(applicationNumber); 15 | this.personId = personId; 16 | } 17 | 18 | 19 | public PartOfScoringPerformed(Object source, String cluster, PersonId personId) { 20 | super(source); 21 | this.personId = personId; 22 | } 23 | 24 | 25 | 26 | public PartOfScoringPerformed(Object source, String cluster, ApplicationNumber applicationNumber) { 27 | super(source); 28 | this.applicationNumber = applicationNumber; 29 | this.cluster = cluster; 30 | } 31 | 32 | public ApplicationNumber getApplicationNumber() { 33 | return applicationNumber; 34 | } 35 | 36 | public PersonId getPersonId() { 37 | return personId; 38 | } 39 | 40 | public String getCluster() { 41 | return cluster; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /credit-sales-funnel/src/main/java/com/mploed/dddwithspring/creditsalesfunnel/model/financing/PurchaseCosts.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.creditsalesfunnel.model.financing; 2 | 3 | import javax.persistence.Embeddable; 4 | import java.io.Serializable; 5 | 6 | @Embeddable 7 | public class PurchaseCosts implements Serializable { 8 | private int priceOfLand; 9 | private int purchasePrice; 10 | private int reconstructionCosts; 11 | private int additionalPurchaseCharges; 12 | 13 | public int sum() { 14 | return priceOfLand + purchasePrice + reconstructionCosts + additionalPurchaseCharges; 15 | } 16 | public int getPriceOfLand() { 17 | return priceOfLand; 18 | } 19 | 20 | public void setPriceOfLand(int priceOfLand) { 21 | this.priceOfLand = priceOfLand; 22 | } 23 | 24 | public int getPurchasePrice() { 25 | return purchasePrice; 26 | } 27 | 28 | public void setPurchasePrice(int purchasePrice) { 29 | this.purchasePrice = purchasePrice; 30 | } 31 | 32 | public int getReconstructionCosts() { 33 | return reconstructionCosts; 34 | } 35 | 36 | public void setReconstructionCosts(int reconstructionCosts) { 37 | this.reconstructionCosts = reconstructionCosts; 38 | } 39 | 40 | public int getAdditionalPurchaseCharges() { 41 | return additionalPurchaseCharges; 42 | } 43 | 44 | public void setAdditionalPurchaseCharges(int additionalPurchaseCharges) { 45 | this.additionalPurchaseCharges = additionalPurchaseCharges; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /scoring/adapters-input/src/main/java/com/mploed/dddwithspring/scoring/incoming/creditAgency/AgencyRating.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.incoming.creditAgency; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | 5 | @JsonIgnoreProperties(ignoreUnknown = true) 6 | 7 | public class AgencyRating { 8 | private int points; 9 | private String firstName; 10 | private String lastName; 11 | private String street; 12 | private String postCode; 13 | private String city; 14 | 15 | public int getPoints() { 16 | return points; 17 | } 18 | 19 | public void setPoints(int points) { 20 | this.points = points; 21 | } 22 | 23 | public String getFirstName() { 24 | return firstName; 25 | } 26 | 27 | public void setFirstName(String firstName) { 28 | this.firstName = firstName; 29 | } 30 | 31 | public String getLastName() { 32 | return lastName; 33 | } 34 | 35 | public void setLastName(String lastName) { 36 | this.lastName = lastName; 37 | } 38 | 39 | public String getStreet() { 40 | return street; 41 | } 42 | 43 | public void setStreet(String street) { 44 | this.street = street; 45 | } 46 | 47 | public String getPostCode() { 48 | return postCode; 49 | } 50 | 51 | public void setPostCode(String postCode) { 52 | this.postCode = postCode; 53 | } 54 | 55 | public String getCity() { 56 | return city; 57 | } 58 | 59 | public void setCity(String city) { 60 | this.city = city; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /credit-agency/src/main/java/com/mploed/dddwithspring/creditagency/model/RatingModel.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.creditagency.model; 2 | 3 | import javax.persistence.Entity; 4 | import javax.persistence.GeneratedValue; 5 | import javax.persistence.GenerationType; 6 | import javax.persistence.Id; 7 | 8 | @Entity 9 | public class RatingModel { 10 | @Id @GeneratedValue(strategy = GenerationType.TABLE) 11 | private Long id; 12 | 13 | private String category; 14 | 15 | private int points; 16 | 17 | private String inputValue; 18 | 19 | private int start; 20 | 21 | private int end; 22 | 23 | public Long getId() { 24 | return id; 25 | } 26 | 27 | public void setId(Long id) { 28 | this.id = id; 29 | } 30 | 31 | public String getCategory() { 32 | return category; 33 | } 34 | 35 | public void setCategory(String category) { 36 | this.category = category; 37 | } 38 | 39 | public int getPoints() { 40 | return points; 41 | } 42 | 43 | public void setPoints(int points) { 44 | this.points = points; 45 | } 46 | 47 | public String getInputValue() { 48 | return inputValue; 49 | } 50 | 51 | public void setInputValue(String inputValue) { 52 | this.inputValue = inputValue; 53 | } 54 | 55 | public int getStart() { 56 | return start; 57 | } 58 | 59 | public void setStart(int start) { 60 | this.start = start; 61 | } 62 | 63 | public int getEnd() { 64 | return end; 65 | } 66 | 67 | public void setEnd(int end) { 68 | this.end = end; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /scoring/aggregates/src/main/java/com/mploed/dddwithspring/scoring/scoringResult/ScoringCalculationResults.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.scoringResult; 2 | 3 | class ScoringCalculationResults { 4 | final int applicantScoringResult; 5 | final int financialSituationScoringResult; 6 | final int agencyScoringResult; 7 | final boolean noGoCriteriaPresent; 8 | 9 | ScoringCalculationResults(int applicantScoringResult, int financialSituationScoringResult, int agencyScoringResult, boolean noGoCriteriaPresent) { 10 | this.applicantScoringResult = applicantScoringResult; 11 | this.financialSituationScoringResult = financialSituationScoringResult; 12 | this.agencyScoringResult = agencyScoringResult; 13 | this.noGoCriteriaPresent = noGoCriteriaPresent; 14 | } 15 | 16 | OverallScoringResult calculateOverallResult() { 17 | System.out.println("Applicant Result: " + applicantScoringResult); 18 | System.out.println("FinancialSituation Result: " + financialSituationScoringResult); 19 | System.out.println("CreditAgency Result: " + agencyScoringResult); 20 | int overallPoints = applicantScoringResult + financialSituationScoringResult + agencyScoringResult; 21 | ScoringColor color; 22 | 23 | if(noGoCriteriaPresent) { 24 | color = ScoringColor.RED; 25 | } else { 26 | if (overallPoints > 40) { 27 | color = ScoringColor.GREEN; 28 | } else { 29 | color = ScoringColor.RED; 30 | } 31 | } 32 | return new OverallScoringResult(overallPoints, color); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /scoring/sharedmodel/src/main/java/com/mploed/dddwithspring/scoring/Money.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring; 2 | 3 | import java.math.BigDecimal; 4 | import java.util.Objects; 5 | 6 | public final class Money { 7 | private final static int DEFAULT_SCALE = 2; 8 | private BigDecimal amount; 9 | private int scale; 10 | 11 | public Money() { 12 | this(BigDecimal.ZERO); 13 | } 14 | 15 | public Money(BigDecimal amount) { 16 | this.amount = amount; 17 | this.scale = DEFAULT_SCALE; 18 | } 19 | 20 | public Money(int amount) { 21 | this(new BigDecimal(amount)); 22 | } 23 | 24 | public Money add(Money money) { 25 | BigDecimal total = this.getAmount().add(money.getAmount()); 26 | 27 | return new Money(total); 28 | } 29 | 30 | public boolean isGreaterThan(Money comparison) { 31 | return this.getAmount().compareTo(comparison.getAmount()) > 0; 32 | } 33 | 34 | public BigDecimal getAmount() { 35 | return amount; 36 | } 37 | 38 | @Override 39 | public String toString() { 40 | return "Money{" + 41 | "amount=" + amount + 42 | ", scale=" + scale + 43 | '}'; 44 | } 45 | 46 | @Override 47 | public boolean equals(Object o) { 48 | if (this == o) return true; 49 | if (o == null || getClass() != o.getClass()) return false; 50 | Money money = (Money) o; 51 | return scale == money.scale && 52 | Objects.equals(amount, money.amount); 53 | } 54 | 55 | @Override 56 | public int hashCode() { 57 | 58 | return Objects.hash(amount, scale); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /scoring/adapters-input/src/main/resources/static/app.js: -------------------------------------------------------------------------------- 1 | var stompClient = null; 2 | 3 | function setConnected(connected) { 4 | $("#connect").prop("disabled", connected); 5 | $("#disconnect").prop("disabled", !connected); 6 | if (connected) { 7 | $("#conversation").show(); 8 | } 9 | else { 10 | $("#conversation").hide(); 11 | } 12 | $("#greetings").html(""); 13 | } 14 | 15 | function connect() { 16 | var socket = new SockJS('/scoring/gs-guide-websocket'); 17 | stompClient = Stomp.over(socket); 18 | stompClient.connect({}, function (frame) { 19 | setConnected(true); 20 | console.log('Connected: ' + frame); 21 | stompClient.subscribe('/topic/greetings', function (greeting) { 22 | console.log('received: ' + greeting) 23 | showGreeting(JSON.parse(greeting.body).content); 24 | }); 25 | }); 26 | } 27 | 28 | function disconnect() { 29 | if (stompClient !== null) { 30 | stompClient.disconnect(); 31 | } 32 | setConnected(false); 33 | console.log("Disconnected"); 34 | } 35 | 36 | function showGreeting(message) { 37 | $("#greetings").append("" + message + ""); 38 | } 39 | 40 | $(function () { 41 | $("form").on('submit', function (e) { 42 | e.preventDefault(); 43 | }); 44 | $( "#connect" ).click(function() { connect(); }); 45 | $( "#disconnect" ).click(function() { disconnect(); }); 46 | $( "#send" ).click(function() { sendName(); }); 47 | }); -------------------------------------------------------------------------------- /credit-agency/src/main/java/com/mploed/dddwithspring/creditagency/service/PersonRatingQueryService.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.creditagency.service; 2 | 3 | import com.mploed.dddwithspring.creditagency.model.PersonRating; 4 | import com.mploed.dddwithspring.creditagency.repository.PersonRatingRepository; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.stereotype.Service; 7 | 8 | import java.util.Calendar; 9 | import java.util.Date; 10 | import java.util.GregorianCalendar; 11 | 12 | @Service 13 | public class PersonRatingQueryService { 14 | private PersonRatingRepository personRatingRepository; 15 | 16 | @Autowired 17 | public PersonRatingQueryService(PersonRatingRepository personRatingRepository) { 18 | this.personRatingRepository = personRatingRepository; 19 | } 20 | 21 | public void ratePerson(String firstName, String lastName, String street, String postCode, String city) { 22 | PersonRating rating = new PersonRating(); 23 | rating.setCity(city); 24 | rating.setFirstName(firstName); 25 | rating.setLastName(lastName); 26 | rating.setPostCode(postCode); 27 | rating.setStreet(street); 28 | rating.setPoints(100); 29 | rating.setLastUpdated(new Date()); 30 | GregorianCalendar gregorianCalendar = new GregorianCalendar(); 31 | gregorianCalendar.add(Calendar.MONTH, 1); 32 | System.out.println(gregorianCalendar.getTime()); 33 | rating.setValidTo(gregorianCalendar.getTime()); 34 | personRatingRepository.save(rating); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /scoring/adapters-output/src/test/java/com/mploed/dddwithspring/scoring/AgencyResultRepositoryTest.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring; 2 | 3 | import com.mploed.dddwithspring.scoring.agencyResult.AgencyResultAggregate; 4 | import com.mploed.dddwithspring.scoring.agencyResult.AgencyResultJPARepository; 5 | import org.junit.Test; 6 | import org.junit.runner.RunWith; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; 9 | import org.springframework.boot.test.context.SpringBootTest; 10 | import org.springframework.test.context.junit4.SpringRunner; 11 | 12 | import static org.assertj.core.api.AssertionsForClassTypes.assertThat; 13 | 14 | @RunWith(SpringRunner.class) 15 | @SpringBootTest 16 | public class AgencyResultRepositoryTest { 17 | @Autowired 18 | private AgencyResultJPARepository repository; 19 | 20 | @Test 21 | public void testSave() { 22 | AgencyResultAggregate aggregate = new AgencyResultAggregate.AgencyResultBuilder() 23 | .forPerson("Michael", "Plöd", "teststr", "40789", "Testcity") 24 | .withPoints(100) 25 | .withWarning("234", "test") 26 | .withKoCriteria("123", "test test") 27 | .withKoCriteria("342", "testing") 28 | .build(); 29 | 30 | repository.save(aggregate); 31 | 32 | AgencyResultAggregate resultAggregate = repository.retrieve(aggregate.getPersonId()); 33 | 34 | assertThat(resultAggregate.getPersonId().toString()).isEqualTo(aggregate.getPersonId().toString()); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /scoring/application-services/src/main/java/com/mploed/dddwithspring/scoring/appservices/internalevents/ScoringPerformed.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.appservices.internalevents; 2 | 3 | import com.mploed.dddwithspring.scoring.ApplicationNumber; 4 | import com.mploed.dddwithspring.scoring.PersonId; 5 | import org.springframework.context.ApplicationEvent; 6 | 7 | public class ScoringPerformed extends ApplicationEvent { 8 | private ApplicationNumber applicationNumber; 9 | private PersonId personId; 10 | private String scoreColor; 11 | private int points; 12 | 13 | public ScoringPerformed(Object source, String applicationNumber, PersonId personId, String scoreColor, int points) { 14 | super(source); 15 | this.applicationNumber = new ApplicationNumber(applicationNumber); 16 | this.personId = personId; 17 | this.scoreColor = scoreColor; 18 | this.points = points; 19 | } 20 | 21 | 22 | public ScoringPerformed(Object source, PersonId personId) { 23 | super(source); 24 | this.personId = personId; 25 | } 26 | 27 | 28 | 29 | public ScoringPerformed(Object source, ApplicationNumber applicationNumber) { 30 | super(source); 31 | this.applicationNumber = applicationNumber; 32 | } 33 | 34 | public ApplicationNumber getApplicationNumber() { 35 | return applicationNumber; 36 | } 37 | 38 | public PersonId getPersonId() { 39 | return personId; 40 | } 41 | 42 | public String getScoreColor() { 43 | return scoreColor; 44 | } 45 | 46 | public int getPoints() { 47 | return points; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ddd-with-spring 2 | 3 |
4 | 5 | [![Build Status](https://travis-ci.org/mploed/ddd-with-spring.svg?branch=master)](https://travis-ci.org/mploed/ddd-with-spring) 6 | 7 |
8 | 9 | This repository aims at showcasing a way how you could implement various aspects from Domain-driven Design with the 10 | Spring ecosystem. It is also the demo project for my conference talk "Implementing Domain-driven Design with the Spring 11 | ecosystem". 12 | 13 | ## Which DDD aspects are covered? 14 | The focus of the demo project are Aggregates, event-based communication and bounded contexts. The complete list is: 15 | 16 | - Aggregates 17 | - Event-based communication with 18 | - a message broker (RabbitMQ) 19 | - HTTP Feeds 20 | - Spring Application Events 21 | - Architectural styles 22 | - Hexagonal Architecture 23 | - CRUD 24 | - Query-driven (not yet implemented properly) 25 | 26 | ## Which Spring Technologies are being used? 27 | 28 | The project uses the following Spring technologies: 29 | 30 | - Spring Framework Core 31 | - Spring MVC 32 | - Spring Boot 33 | - Spring Cloud Stream 34 | - Spring Data JPA 35 | 36 | ## Prerequisites and getting started 37 | 38 | In order to run the application you need to have Docker and docker-compose installed on your machine. 39 | 40 | When you have docker up and running you need to perform the following steps on the command line: 41 | 42 | 1. ./mvnw clean package 43 | 2. docker-compose up --build 44 | 3. After everything has started you can open http://localhost:8080 in a browser of your choice 45 | -------------------------------------------------------------------------------- /credit-agency/src/main/java/com/mploed/dddwithspring/creditagency/messaging/IncomingMessageListener.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.creditagency.messaging; 2 | 3 | import com.mploed.dddwithspring.creditagency.events.incoming.ApplicationSubmittedEvent; 4 | import com.mploed.dddwithspring.creditagency.events.incoming.applicant.Applicant; 5 | import com.mploed.dddwithspring.creditagency.service.PersonRatingQueryService; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.cloud.stream.annotation.StreamListener; 8 | import org.springframework.messaging.handler.annotation.Payload; 9 | import org.springframework.stereotype.Component; 10 | 11 | @Component 12 | public class IncomingMessageListener { 13 | 14 | private PersonRatingQueryService personRatingQueryService; 15 | 16 | @Autowired 17 | public IncomingMessageListener(PersonRatingQueryService personRatingQueryService) { 18 | this.personRatingQueryService = personRatingQueryService; 19 | } 20 | 21 | @StreamListener(CreditAgencyChannels.APPLICATION_SUBMITTED) 22 | public void receiveApplicationSubmission(@Payload ApplicationSubmittedEvent applicationSubmittedEvent) { 23 | 24 | System.out.println("received " + applicationSubmittedEvent.getFirstApplicant().toString()); 25 | Applicant applicant = applicationSubmittedEvent.getFirstApplicant(); 26 | personRatingQueryService.ratePerson(applicant.getFirstName(), 27 | applicant.getLastName(), 28 | applicant.getAddress().getStreet(), 29 | applicant.getAddress().getPostCode(), 30 | applicant.getAddress().getCity()); 31 | } 32 | 33 | 34 | } 35 | -------------------------------------------------------------------------------- /credit-sales-funnel/src/main/java/com/mploed/dddwithspring/creditsalesfunnel/model/applicant/Address.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.creditsalesfunnel.model.applicant; 2 | 3 | import com.mploed.dddwithspring.creditsalesfunnel.model.validation.ApplicationSubmissionGroup; 4 | 5 | import javax.persistence.Embeddable; 6 | import javax.validation.constraints.NotEmpty; 7 | import javax.validation.constraints.NotNull; 8 | import java.io.Serializable; 9 | 10 | @Embeddable 11 | public class Address implements Serializable { 12 | @NotNull(groups = ApplicationSubmissionGroup.class) 13 | @NotEmpty(groups = ApplicationSubmissionGroup.class) 14 | private String street; 15 | 16 | @NotNull(groups = ApplicationSubmissionGroup.class) 17 | @NotEmpty(groups = ApplicationSubmissionGroup.class) 18 | private String postCode; 19 | 20 | @NotNull(groups = ApplicationSubmissionGroup.class) 21 | @NotEmpty(groups = ApplicationSubmissionGroup.class) 22 | private String city; 23 | 24 | public String getStreet() { 25 | return street; 26 | } 27 | 28 | public String getPostCode() { 29 | return postCode; 30 | } 31 | 32 | public String getCity() { 33 | return city; 34 | } 35 | 36 | public void setStreet(String street) { 37 | this.street = street; 38 | } 39 | 40 | public void setPostCode(String postCode) { 41 | this.postCode = postCode; 42 | } 43 | 44 | public void setCity(String city) { 45 | this.city = city; 46 | } 47 | 48 | @Override 49 | public String toString() { 50 | return "Address{" + 51 | "street='" + street + '\'' + 52 | ", postCode='" + postCode + '\'' + 53 | ", city='" + city + '\'' + 54 | '}'; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /scoring/adapters-input/src/main/java/com/mploed/dddwithspring/scoring/incoming/financing/Loan.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.incoming.financing; 2 | 3 | import javax.persistence.Entity; 4 | import javax.persistence.GeneratedValue; 5 | import javax.persistence.GenerationType; 6 | import javax.persistence.Id; 7 | import java.io.Serializable; 8 | 9 | public class Loan implements Serializable { 10 | private Long databaseId; 11 | private int loanAmount; 12 | private int interestRate; 13 | private int repaymentInPercent; 14 | private int fixedInterestRateInYears; 15 | 16 | public Loan() { 17 | this.interestRate = 2; 18 | } 19 | 20 | public Long getDatabaseId() { 21 | return databaseId; 22 | } 23 | 24 | public void setDatabaseId(Long databaseId) { 25 | this.databaseId = databaseId; 26 | } 27 | 28 | public int getLoanAmount() { 29 | return loanAmount; 30 | } 31 | 32 | public void setLoanAmount(int loanAmount) { 33 | this.loanAmount = loanAmount; 34 | } 35 | 36 | public int getInterestRate() { 37 | return interestRate; 38 | } 39 | 40 | public void setInterestRate(int interestRate) { 41 | this.interestRate = interestRate; 42 | } 43 | 44 | public int getRepaymentInPercent() { 45 | return repaymentInPercent; 46 | } 47 | 48 | public void setRepaymentInPercent(int repaymentInPercent) { 49 | this.repaymentInPercent = repaymentInPercent; 50 | } 51 | 52 | public int getFixedInterestRateInYears() { 53 | return fixedInterestRateInYears; 54 | } 55 | 56 | public void setFixedInterestRateInYears(int fixedInterestRateInYears) { 57 | this.fixedInterestRateInYears = fixedInterestRateInYears; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /credit-agency/src/main/java/com/mploed/dddwithspring/creditagency/web/PersonRatingController.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.creditagency.web; 2 | 3 | import com.mploed.dddwithspring.creditagency.repository.PersonRatingRepository; 4 | import org.springframework.data.domain.Sort; 5 | import org.springframework.stereotype.Controller; 6 | import org.springframework.ui.Model; 7 | import org.springframework.web.bind.annotation.GetMapping; 8 | import org.springframework.web.bind.annotation.RequestMapping; 9 | import org.springframework.web.context.request.WebRequest; 10 | import org.springframework.web.servlet.ModelAndView; 11 | 12 | import javax.servlet.http.HttpServletResponse; 13 | import java.util.Date; 14 | 15 | @Controller 16 | @RequestMapping("person-rating") 17 | public class PersonRatingController { 18 | private PersonRatingRepository personRatingRepository; 19 | 20 | public PersonRatingController(PersonRatingRepository personRatingRepository) { 21 | this.personRatingRepository = personRatingRepository; 22 | } 23 | 24 | @RequestMapping(value = "/feed", produces = "application/atom+xml") 25 | public ModelAndView orderFeed(WebRequest webRequest, HttpServletResponse response) { 26 | 27 | Date lastUpdate = personRatingRepository.lastUpdate(); 28 | // null handling for a new start of the application with no current ratings in it 29 | if(lastUpdate != null) { 30 | response.setDateHeader("Last-Modified", lastUpdate.getTime()); 31 | } 32 | 33 | Sort sort = new Sort(Sort.Direction.ASC, "lastUpdated"); 34 | return new ModelAndView(new PersonRatingAtomFeedView(personRatingRepository), "personRatings", personRatingRepository.findAll(sort)); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /credit-sales-funnel/src/main/java/com/mploed/dddwithspring/creditsalesfunnel/model/realEstate/ApartmentInformation.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.creditsalesfunnel.model.realEstate; 2 | 3 | import com.mploed.dddwithspring.creditsalesfunnel.model.validation.ApplicationSubmissionGroup; 4 | 5 | import javax.persistence.Embeddable; 6 | import javax.validation.constraints.Min; 7 | import javax.validation.constraints.NotEmpty; 8 | import javax.validation.constraints.NotNull; 9 | import java.io.Serializable; 10 | 11 | @Embeddable 12 | public class ApartmentInformation implements Serializable { 13 | @Min(value = 1, groups = ApplicationSubmissionGroup.class) 14 | private int numberOfApartmentsInHouse; 15 | 16 | @NotNull(groups = ApplicationSubmissionGroup.class) 17 | @NotEmpty(groups = ApplicationSubmissionGroup.class) 18 | private String nameOfApartment; 19 | 20 | @NotNull(groups = ApplicationSubmissionGroup.class) 21 | private ApartmentLocation apartmentLocation; 22 | 23 | public int getNumberOfApartmentsInHouse() { 24 | return numberOfApartmentsInHouse; 25 | } 26 | 27 | public void setNumberOfApartmentsInHouse(int numberOfApartmentsInHouse) { 28 | this.numberOfApartmentsInHouse = numberOfApartmentsInHouse; 29 | } 30 | 31 | public String getNameOfApartment() { 32 | return nameOfApartment; 33 | } 34 | 35 | public void setNameOfApartment(String nameOfApartment) { 36 | this.nameOfApartment = nameOfApartment; 37 | } 38 | 39 | public ApartmentLocation getApartmentLocation() { 40 | return apartmentLocation; 41 | } 42 | 43 | public void setApartmentLocation(ApartmentLocation apartmentLocation) { 44 | this.apartmentLocation = apartmentLocation; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /credit-sales-funnel/src/main/resources/templates/layout/baseIndex.html: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 13 | 14 | 15 | Big Pug Loans 16 | 17 | 18 | 19 | 20 |
21 | Whatever content there is 22 |
23 | 24 | 25 | 26 | 27 | 30 | 33 | 36 | 37 | -------------------------------------------------------------------------------- /credit-sales-funnel/src/main/java/com/mploed/dddwithspring/creditsalesfunnel/model/financing/Loan.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.creditsalesfunnel.model.financing; 2 | 3 | import javax.persistence.Entity; 4 | import javax.persistence.GeneratedValue; 5 | import javax.persistence.GenerationType; 6 | import javax.persistence.Id; 7 | import java.io.Serializable; 8 | 9 | @Entity 10 | public class Loan implements Serializable { 11 | @Id 12 | @GeneratedValue(strategy = GenerationType.TABLE) 13 | private Long databaseId; 14 | private int loanAmount; 15 | private int interestRate; 16 | private int repaymentInPercent; 17 | private int fixedInterestRateInYears; 18 | 19 | public Loan() { 20 | this.interestRate = 2; 21 | } 22 | 23 | public Long getDatabaseId() { 24 | return databaseId; 25 | } 26 | 27 | public void setDatabaseId(Long databaseId) { 28 | this.databaseId = databaseId; 29 | } 30 | 31 | public int getLoanAmount() { 32 | return loanAmount; 33 | } 34 | 35 | public void setLoanAmount(int loanAmount) { 36 | this.loanAmount = loanAmount; 37 | } 38 | 39 | public int getInterestRate() { 40 | return interestRate; 41 | } 42 | 43 | public void setInterestRate(int interestRate) { 44 | this.interestRate = interestRate; 45 | } 46 | 47 | public int getRepaymentInPercent() { 48 | return repaymentInPercent; 49 | } 50 | 51 | public void setRepaymentInPercent(int repaymentInPercent) { 52 | this.repaymentInPercent = repaymentInPercent; 53 | } 54 | 55 | public int getFixedInterestRateInYears() { 56 | return fixedInterestRateInYears; 57 | } 58 | 59 | public void setFixedInterestRateInYears(int fixedInterestRateInYears) { 60 | this.fixedInterestRateInYears = fixedInterestRateInYears; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /scoring/aggregates/src/main/java/com/mploed/dddwithspring/scoring/agencyResult/AgencyResultRootEntity.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.agencyResult; 2 | 3 | 4 | import com.mploed.dddwithspring.scoring.PersonId; 5 | import java.util.Collection; 6 | import java.util.HashSet; 7 | import java.util.Set; 8 | 9 | class AgencyResultRootEntity { 10 | final PersonId id; 11 | final int points; 12 | private final Set koCriteria; 13 | private final Set warningMessages; 14 | 15 | AgencyResultRootEntity(PersonId id, int points) { 16 | this.id = id; 17 | this.points = points; 18 | this.koCriteria = new HashSet(); 19 | this.warningMessages = new HashSet(); 20 | } 21 | 22 | Set getKoCriteria() { 23 | return koCriteria; 24 | } 25 | 26 | Set getWarningMessages() { 27 | return warningMessages; 28 | } 29 | 30 | void addAllKoCriteria(Collection koCriteria) { 31 | this.koCriteria.addAll(koCriteria); 32 | } 33 | 34 | void addAllWarningMessage(Collection warningMessages) { 35 | this.warningMessages.addAll(warningMessages); 36 | } 37 | 38 | boolean isAcceptable() { 39 | if (koCriteria.size() > 0) { 40 | return false; 41 | } else if (warningMessages.size() > 5) { 42 | return false; 43 | } else { 44 | return true; 45 | } 46 | } 47 | 48 | int calculateScoringPoints() { 49 | int result = 0; 50 | if (koCriteria.size() > 0) { 51 | return result; 52 | } 53 | if (warningMessages.size() == 0) { 54 | result += 5; 55 | } 56 | if (points > 90) { 57 | result += 15; 58 | } else if (points > 85) { 59 | result += 10; 60 | } else if (points > 80) { 61 | result += 5; 62 | } 63 | return result; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /scoring/adapters-output/src/main/java/com/mploed/dddwithspring/scoring/financialSituation/FinancialSituationResultProjection.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.financialSituation; 2 | 3 | import javax.persistence.Entity; 4 | import javax.persistence.GeneratedValue; 5 | import javax.persistence.Id; 6 | import java.math.BigDecimal; 7 | 8 | @Entity 9 | public class FinancialSituationResultProjection { 10 | @Id 11 | @GeneratedValue 12 | private Long id; 13 | private String applicationNumber; 14 | 15 | private BigDecimal incomingOther; 16 | private BigDecimal incomingSalary; 17 | 18 | private BigDecimal outgoingRent; 19 | private BigDecimal outgoingCostOfLiving; 20 | 21 | Long getId() { 22 | return id; 23 | } 24 | 25 | void setId(Long id) { 26 | this.id = id; 27 | } 28 | 29 | String getApplicationNumber() { 30 | return applicationNumber; 31 | } 32 | 33 | void setApplicationNumber(String applicationNumber) { 34 | this.applicationNumber = applicationNumber; 35 | } 36 | 37 | BigDecimal getIncomingOther() { 38 | return incomingOther; 39 | } 40 | 41 | void setIncomingOther(BigDecimal incomingOther) { 42 | this.incomingOther = incomingOther; 43 | } 44 | 45 | BigDecimal getIncomingSalary() { 46 | return incomingSalary; 47 | } 48 | 49 | void setIncomingSalary(BigDecimal incomingSalary) { 50 | this.incomingSalary = incomingSalary; 51 | } 52 | 53 | BigDecimal getOutgoingRent() { 54 | return outgoingRent; 55 | } 56 | 57 | void setOutgoingRent(BigDecimal outgoingRent) { 58 | this.outgoingRent = outgoingRent; 59 | } 60 | 61 | BigDecimal getOutgoingCostOfLiving() { 62 | return outgoingCostOfLiving; 63 | } 64 | 65 | void setOutgoingCostOfLiving(BigDecimal outgoingCostOfLiving) { 66 | this.outgoingCostOfLiving = outgoingCostOfLiving; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /scoring/adapters-output/src/main/java/com/mploed/dddwithspring/scoring/agencyResult/AgencyResultProjection.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.agencyResult; 2 | 3 | import javax.persistence.ElementCollection; 4 | import javax.persistence.Entity; 5 | import javax.persistence.GeneratedValue; 6 | import javax.persistence.Id; 7 | import java.util.HashSet; 8 | import java.util.Set; 9 | 10 | @Entity 11 | public class AgencyResultProjection { 12 | @Id 13 | @GeneratedValue 14 | private Long id; 15 | private String personId; 16 | private int points; 17 | 18 | @ElementCollection 19 | private Set koCriteria = new HashSet<>(); 20 | 21 | @ElementCollection 22 | private Set warnings = new HashSet<>(); 23 | 24 | private Long getId() { 25 | return id; 26 | } 27 | 28 | private void setId(Long id) { 29 | this.id = id; 30 | } 31 | 32 | public String getPersonId() { 33 | return personId; 34 | } 35 | 36 | public void setPersonId(String personId) { 37 | this.personId = personId; 38 | } 39 | 40 | public int getPoints() { 41 | return points; 42 | } 43 | 44 | public void setPoints(int points) { 45 | this.points = points; 46 | } 47 | 48 | public Set getKoCriteria() { 49 | return koCriteria; 50 | } 51 | 52 | public void setKoCriteria(Set koCriteria) { 53 | this.koCriteria = koCriteria; 54 | } 55 | 56 | public Set getWarnings() { 57 | return warnings; 58 | } 59 | 60 | public void setWarnings(Set warnings) { 61 | this.warnings = warnings; 62 | } 63 | 64 | public void addWarning(AgencyMessage agencyMessage) { 65 | this.warnings.add(agencyMessage); 66 | } 67 | 68 | public void addKoCriteria(AgencyMessage agencyMessage) { 69 | this.koCriteria.add(agencyMessage); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /scoring/adapters-input/src/main/java/com/mploed/dddwithspring/scoring/incoming/AgencyResultArrivedEvent.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.incoming; 2 | 3 | 4 | import java.util.Set; 5 | 6 | public class AgencyResultArrivedEvent { 7 | private String firstName; 8 | private String lastName; 9 | private String street; 10 | private String postCode; 11 | private String city; 12 | 13 | private int points; 14 | private Set koCriteria; 15 | private Set warningMessages; 16 | 17 | 18 | public String getFirstName() { 19 | return firstName; 20 | } 21 | 22 | public void setFirstName(String firstName) { 23 | this.firstName = firstName; 24 | } 25 | 26 | public String getLastName() { 27 | return lastName; 28 | } 29 | 30 | public void setLastName(String lastName) { 31 | this.lastName = lastName; 32 | } 33 | 34 | public String getStreet() { 35 | return street; 36 | } 37 | 38 | public void setStreet(String street) { 39 | this.street = street; 40 | } 41 | 42 | public String getPostCode() { 43 | return postCode; 44 | } 45 | 46 | public void setPostCode(String postCode) { 47 | this.postCode = postCode; 48 | } 49 | 50 | public String getCity() { 51 | return city; 52 | } 53 | 54 | public void setCity(String city) { 55 | this.city = city; 56 | } 57 | 58 | public int getPoints() { 59 | return points; 60 | } 61 | 62 | public void setPoints(int points) { 63 | this.points = points; 64 | } 65 | 66 | public Set getKoCriteria() { 67 | return koCriteria; 68 | } 69 | 70 | public void setKoCriteria(Set koCriteria) { 71 | this.koCriteria = koCriteria; 72 | } 73 | 74 | public Set getWarningMessages() { 75 | return warningMessages; 76 | } 77 | 78 | public void setWarningMessages(Set warningMessages) { 79 | this.warningMessages = warningMessages; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /credit-agency/src/main/java/com/mploed/dddwithspring/creditagency/model/PersonRating.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.creditagency.model; 2 | 3 | import javax.persistence.*; 4 | import java.io.Serializable; 5 | import java.util.Date; 6 | 7 | @Entity 8 | public class PersonRating implements Serializable { 9 | @Id @GeneratedValue(strategy = GenerationType.TABLE) 10 | private Long id; 11 | 12 | @Temporal(TemporalType.TIMESTAMP) 13 | private Date validTo; 14 | private Date lastUpdated; 15 | private int points; 16 | private String firstName; 17 | private String lastName; 18 | private String street; 19 | private String postCode; 20 | private String city; 21 | 22 | 23 | public Long getId() { 24 | return id; 25 | } 26 | 27 | public void setId(Long id) { 28 | this.id = id; 29 | } 30 | 31 | public Date getLastUpdated() { 32 | return lastUpdated; 33 | } 34 | 35 | public void setLastUpdated(Date lastUpdated) { 36 | this.lastUpdated = lastUpdated; 37 | } 38 | 39 | public Date getValidTo() { 40 | return validTo; 41 | } 42 | 43 | public void setValidTo(Date validTo) { 44 | this.validTo = validTo; 45 | } 46 | 47 | public int getPoints() { 48 | return points; 49 | } 50 | 51 | public void setPoints(int points) { 52 | this.points = points; 53 | } 54 | 55 | public String getFirstName() { 56 | return firstName; 57 | } 58 | 59 | public void setFirstName(String firstName) { 60 | this.firstName = firstName; 61 | } 62 | 63 | public String getLastName() { 64 | return lastName; 65 | } 66 | 67 | public void setLastName(String lastName) { 68 | this.lastName = lastName; 69 | } 70 | 71 | public String getStreet() { 72 | return street; 73 | } 74 | 75 | public void setStreet(String street) { 76 | this.street = street; 77 | } 78 | 79 | public String getPostCode() { 80 | return postCode; 81 | } 82 | 83 | public void setPostCode(String postCode) { 84 | this.postCode = postCode; 85 | } 86 | 87 | public String getCity() { 88 | return city; 89 | } 90 | 91 | public void setCity(String city) { 92 | this.city = city; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /scoring/aggregates/jqassistant/my-rules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | All JUnit test classes must have a name with suffix "Test". 6 | 14 | 15 | 16 | 17 | All Classes annotated with @Aggregate must have a name ending with Aggregate 18 | (annotation:Java:Annotation) 21 | -[:OF_TYPE]->(type:Java {fqn:'com.mploed.dddwithspring.scoring.microarchitecture.Aggregate'}) 22 | WHERE NOT element.name ENDS WITH 'Aggregate' 23 | RETURN element.fqn AS InvalidAggregateName 24 | ]]> 25 | 26 | 27 | 28 | All Classes annotated with @AggregateBuilder must be called Builder 29 | (annotation:Java:Annotation) 32 | -[:OF_TYPE]->(type:Java {fqn:'com.mploed.dddwithspring.scoring.microarchitecture.AggregateBuilder'}) 33 | WHERE NOT element.name ENDS WITH 'Builder' 34 | RETURN element.fqn AS InvalidBuilderName 35 | ]]> 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /scoring/adapters-output/src/main/java/com/mploed/dddwithspring/scoring/applicant/ApplicantResultProjection.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.applicant; 2 | 3 | import javax.persistence.Entity; 4 | import javax.persistence.GeneratedValue; 5 | import javax.persistence.Id; 6 | import java.math.BigDecimal; 7 | 8 | @Entity 9 | public class ApplicantResultProjection { 10 | @Id 11 | @GeneratedValue 12 | private Long id; 13 | private String personId; 14 | private String applicationNumber; 15 | private String name; 16 | private String lastName; 17 | private String city; 18 | private String postCode; 19 | private String street; 20 | private BigDecimal balance; 21 | 22 | public Long getId() { 23 | return id; 24 | } 25 | 26 | public void setId(Long id) { 27 | this.id = id; 28 | } 29 | 30 | public String getPersonId() { 31 | return personId; 32 | } 33 | 34 | public void setPersonId(String personId) { 35 | this.personId = personId; 36 | } 37 | 38 | public String getApplicationNumber() { 39 | return applicationNumber; 40 | } 41 | 42 | public void setApplicationNumber(String applicationNumber) { 43 | this.applicationNumber = applicationNumber; 44 | } 45 | 46 | public String getName() { 47 | return name; 48 | } 49 | 50 | public void setName(String name) { 51 | this.name = name; 52 | } 53 | 54 | public String getLastName() { 55 | return lastName; 56 | } 57 | 58 | public void setLastName(String lastName) { 59 | this.lastName = lastName; 60 | } 61 | 62 | public String getCity() { 63 | return city; 64 | } 65 | 66 | public void setCity(String city) { 67 | this.city = city; 68 | } 69 | 70 | public String getPostCode() { 71 | return postCode; 72 | } 73 | 74 | public void setPostCode(String postCode) { 75 | this.postCode = postCode; 76 | } 77 | 78 | public String getStreet() { 79 | return street; 80 | } 81 | 82 | public void setStreet(String street) { 83 | this.street = street; 84 | } 85 | 86 | public BigDecimal getBalance() { 87 | return balance; 88 | } 89 | 90 | public void setBalance(BigDecimal balance) { 91 | this.balance = balance; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /scoring/adapters-input/src/main/java/com/mploed/dddwithspring/scoring/web/WebSocketController.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.web; 2 | 3 | import com.mploed.dddwithspring.scoring.appservices.internalevents.CreditAgencyResultArrived; 4 | import com.mploed.dddwithspring.scoring.appservices.internalevents.CreditApplicationArrived; 5 | import com.mploed.dddwithspring.scoring.appservices.internalevents.PartOfScoringPerformed; 6 | import com.mploed.dddwithspring.scoring.appservices.internalevents.ScoringPerformed; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.context.event.EventListener; 9 | import org.springframework.messaging.simp.SimpMessagingTemplate; 10 | import org.springframework.stereotype.Controller; 11 | 12 | @Controller 13 | public class WebSocketController { 14 | private SimpMessagingTemplate template; 15 | 16 | @Autowired 17 | public WebSocketController(SimpMessagingTemplate template) { 18 | this.template = template; 19 | } 20 | 21 | 22 | @EventListener 23 | public void greeting(PartOfScoringPerformed event) throws Exception { 24 | this.template.convertAndSend("/topic/greetings", new WebSocketMessage(event.getCluster() + " has been scored for Application Number: " + event.getApplicationNumber())); 25 | } 26 | 27 | @EventListener 28 | public void greeting(ScoringPerformed event) throws Exception { 29 | this.template.convertAndSend("/topic/greetings", new WebSocketMessage(event.getApplicationNumber() + " has been scored with " + event.getPoints() + " and final result " + event.getScoreColor())); 30 | } 31 | 32 | @EventListener 33 | public void greeting(CreditAgencyResultArrived event) throws Exception { 34 | this.template.convertAndSend("/topic/greetings", new WebSocketMessage("Credit Agency Result has arrived for Person" + event.getPersonId().toString())); 35 | } 36 | 37 | @EventListener 38 | public void greeting(CreditApplicationArrived event) throws Exception { 39 | this.template.convertAndSend("/topic/greetings", new WebSocketMessage("Credit Application has arrived with ID " + event.getApplicationNumber().toString())); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /credit-sales-funnel/src/main/java/com/mploed/dddwithspring/creditsalesfunnel/model/CreditApplicationForm.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.creditsalesfunnel.model; 2 | 3 | import com.mploed.dddwithspring.creditsalesfunnel.model.applicant.Applicant; 4 | import com.mploed.dddwithspring.creditsalesfunnel.model.financing.Financing; 5 | import com.mploed.dddwithspring.creditsalesfunnel.model.household.Household; 6 | import com.mploed.dddwithspring.creditsalesfunnel.model.realEstate.RealEstateProperty; 7 | 8 | import java.io.Serializable; 9 | import java.util.UUID; 10 | 11 | public class CreditApplicationForm implements Serializable { 12 | private String applicationNumber; 13 | 14 | private Applicant firstApplicant; 15 | private Applicant secondApplicant; 16 | private RealEstateProperty realEstateProperty; 17 | private Household householdInformation; 18 | private Financing financing; 19 | 20 | public CreditApplicationForm() { 21 | this.applicationNumber = UUID.randomUUID().toString(); 22 | } 23 | 24 | public String getApplicationNumber() { 25 | return applicationNumber; 26 | } 27 | 28 | public Applicant getFirstApplicant() { 29 | return firstApplicant; 30 | } 31 | 32 | public void setFirstApplicant(Applicant firstApplicant) { 33 | this.firstApplicant = firstApplicant; 34 | } 35 | 36 | public Applicant getSecondApplicant() { 37 | return secondApplicant; 38 | } 39 | 40 | public void setSecondApplicant(Applicant secondApplicant) { 41 | this.secondApplicant = secondApplicant; 42 | } 43 | 44 | public RealEstateProperty getRealEstateProperty() { 45 | return realEstateProperty; 46 | } 47 | 48 | public void setRealEstateProperty(RealEstateProperty realEstateProperty) { 49 | this.realEstateProperty = realEstateProperty; 50 | } 51 | 52 | public Household getHouseholdInformation() { 53 | return householdInformation; 54 | } 55 | 56 | public void setHouseholdInformation(Household householdInformation) { 57 | this.householdInformation = householdInformation; 58 | } 59 | 60 | public Financing getFinancing() { 61 | return financing; 62 | } 63 | 64 | public void setFinancing(Financing financing) { 65 | this.financing = financing; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /scoring/adapters-input/src/main/java/com/mploed/dddwithspring/scoring/incoming/household/MonthlyExpenses.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.incoming.household; 2 | 3 | import java.io.Serializable; 4 | 5 | public class MonthlyExpenses implements Serializable { 6 | private int healthInsuranceFirstApplicant; 7 | private int healthInsuranceSecondApplicant; 8 | private int otherLoansRemainderOfDebt; 9 | private int otherLoansMonthlyRepayments; 10 | private int costOfLiving; 11 | private int rent; 12 | private boolean rentNotApplicableInFuture; 13 | 14 | public int getHealthInsuranceFirstApplicant() { 15 | return healthInsuranceFirstApplicant; 16 | } 17 | 18 | public void setHealthInsuranceFirstApplicant(int healthInsuranceFirstApplicant) { 19 | this.healthInsuranceFirstApplicant = healthInsuranceFirstApplicant; 20 | } 21 | 22 | public int getHealthInsuranceSecondApplicant() { 23 | return healthInsuranceSecondApplicant; 24 | } 25 | 26 | public void setHealthInsuranceSecondApplicant(int healthInsuranceSecondApplicant) { 27 | this.healthInsuranceSecondApplicant = healthInsuranceSecondApplicant; 28 | } 29 | 30 | public int getOtherLoansRemainderOfDebt() { 31 | return otherLoansRemainderOfDebt; 32 | } 33 | 34 | public void setOtherLoansRemainderOfDebt(int otherLoansRemainderOfDebt) { 35 | this.otherLoansRemainderOfDebt = otherLoansRemainderOfDebt; 36 | } 37 | 38 | public int getOtherLoansMonthlyRepayments() { 39 | return otherLoansMonthlyRepayments; 40 | } 41 | 42 | public void setOtherLoansMonthlyRepayments(int otherLoansMonthlyRepayments) { 43 | this.otherLoansMonthlyRepayments = otherLoansMonthlyRepayments; 44 | } 45 | 46 | public int getCostOfLiving() { 47 | return costOfLiving; 48 | } 49 | 50 | public void setCostOfLiving(int costOfLiving) { 51 | this.costOfLiving = costOfLiving; 52 | } 53 | 54 | public int getRent() { 55 | return rent; 56 | } 57 | 58 | public void setRent(int rent) { 59 | this.rent = rent; 60 | } 61 | 62 | public boolean isRentNotApplicableInFuture() { 63 | return rentNotApplicableInFuture; 64 | } 65 | 66 | public void setRentNotApplicableInFuture(boolean rentNotApplicableInFuture) { 67 | this.rentNotApplicableInFuture = rentNotApplicableInFuture; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /scoring/adapters-input/src/main/java/com/mploed/dddwithspring/scoring/incoming/ApplicationSubmittedEvent.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.incoming; 2 | 3 | import com.mploed.dddwithspring.scoring.incoming.applicant.Applicant; 4 | import com.mploed.dddwithspring.scoring.incoming.financing.Financing; 5 | import com.mploed.dddwithspring.scoring.incoming.household.Household; 6 | import com.mploed.dddwithspring.scoring.incoming.realEstate.RealEstateProperty; 7 | 8 | import java.util.Date; 9 | 10 | public class ApplicationSubmittedEvent { 11 | private String applicationNumber; 12 | private Date timestamp; 13 | private Applicant firstApplicant; 14 | private Applicant secondApplicant; 15 | private Household household; 16 | private RealEstateProperty realEstateProperty; 17 | private Financing financing; 18 | 19 | public ApplicationSubmittedEvent() { 20 | } 21 | 22 | public String getApplicationNumber() { 23 | return applicationNumber; 24 | } 25 | 26 | public void setApplicationNumber(String applicationNumber) { 27 | this.applicationNumber = applicationNumber; 28 | } 29 | 30 | public Date getTimestamp() { 31 | return timestamp; 32 | } 33 | 34 | public void setTimestamp(Date timestamp) { 35 | this.timestamp = timestamp; 36 | } 37 | 38 | public Applicant getFirstApplicant() { 39 | return firstApplicant; 40 | } 41 | 42 | public void setFirstApplicant(Applicant firstApplicant) { 43 | this.firstApplicant = firstApplicant; 44 | } 45 | 46 | public Applicant getSecondApplicant() { 47 | return secondApplicant; 48 | } 49 | 50 | public void setSecondApplicant(Applicant secondApplicant) { 51 | this.secondApplicant = secondApplicant; 52 | } 53 | 54 | public Household getHousehold() { 55 | return household; 56 | } 57 | 58 | public void setHousehold(Household household) { 59 | this.household = household; 60 | } 61 | 62 | public RealEstateProperty getRealEstateProperty() { 63 | return realEstateProperty; 64 | } 65 | 66 | public void setRealEstateProperty(RealEstateProperty realEstateProperty) { 67 | this.realEstateProperty = realEstateProperty; 68 | } 69 | 70 | public Financing getFinancing() { 71 | return financing; 72 | } 73 | 74 | public void setFinancing(Financing financing) { 75 | this.financing = financing; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /scoring/aggregates/src/main/java/com/mploed/dddwithspring/scoring/scoringResult/ScoringResultAggregate.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.scoringResult; 2 | 3 | 4 | import com.mploed.dddwithspring.scoring.ApplicationNumber; 5 | import com.mploed.dddwithspring.scoring.microarchitecture.Aggregate; 6 | import com.mploed.dddwithspring.scoring.microarchitecture.AggregateBuilder; 7 | 8 | @Aggregate 9 | public class ScoringResultAggregate { 10 | final ScoringResultRootEntity rootEntity; 11 | private ScoringResultAggregate(Builder builder) { 12 | this.rootEntity = new ScoringResultRootEntity(builder.applicationNumber, 13 | builder.applicantScoringResult, 14 | builder.financialSituationScoringResult, 15 | builder.agencyScoringResult, 16 | builder.noGoCriteriaPresent); 17 | } 18 | 19 | public String getScoreColor() { 20 | return this.rootEntity.overallScoringResult.color.toString(); 21 | } 22 | 23 | public int getScorePoints() { 24 | return this.rootEntity.overallScoringResult.points; 25 | } 26 | 27 | @AggregateBuilder 28 | public static class Builder { 29 | private final ApplicationNumber applicationNumber; 30 | private int applicantScoringResult; 31 | private int financialSituationScoringResult; 32 | private int agencyScoringResult; 33 | private boolean noGoCriteriaPresent; 34 | 35 | public Builder(ApplicationNumber applicationNumber) { 36 | this.applicationNumber = applicationNumber; 37 | } 38 | 39 | public Builder applicantScoring(int applicantScoringResult) { 40 | this.applicantScoringResult = applicantScoringResult; 41 | return this; 42 | } 43 | 44 | public Builder financialSituationScoring(int financialSituationScoringResult) { 45 | this.financialSituationScoringResult = financialSituationScoringResult; 46 | return this; 47 | } 48 | 49 | public Builder agencyScoring(int agencyScoringResult) { 50 | this.agencyScoringResult = agencyScoringResult; 51 | return this; 52 | } 53 | 54 | public Builder noGoCriteria(boolean noGoCriteriaPresent) { 55 | this.noGoCriteriaPresent = noGoCriteriaPresent; 56 | return this; 57 | } 58 | 59 | public ScoringResultAggregate build() { 60 | return new ScoringResultAggregate(this); 61 | } 62 | 63 | 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /scoring/adapters-output/src/main/java/com/mploed/dddwithspring/scoring/scoringResult/ScoringResultJPARepository.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.scoringResult; 2 | 3 | import com.mploed.dddwithspring.scoring.ApplicationNumber; 4 | import com.mploed.dddwithspring.scoring.appservices.repositories.ScoringResultRepository; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.stereotype.Component; 7 | import org.springframework.transaction.annotation.Propagation; 8 | import org.springframework.transaction.annotation.Transactional; 9 | 10 | @Component 11 | @Transactional(propagation = Propagation.REQUIRES_NEW) 12 | public class ScoringResultJPARepository implements ScoringResultRepository { 13 | private ScoringResultDAO scoringResultDAO; 14 | 15 | @Autowired 16 | public ScoringResultJPARepository(ScoringResultDAO scoringResultDAO) { 17 | this.scoringResultDAO = scoringResultDAO; 18 | } 19 | 20 | @Override 21 | public void save(ScoringResultAggregate scoringResultAggregate) { 22 | 23 | DetailedScoringResults detailedScoringResults = new DetailedScoringResults(scoringResultAggregate.rootEntity.scoringCalculationResults); 24 | 25 | ScoringResultEntity scoringResultEntity = new ScoringResultEntity(scoringResultAggregate.rootEntity.applicationNumber.toString(), scoringResultAggregate.getScorePoints(), scoringResultAggregate.getScoreColor(), detailedScoringResults); 26 | this.scoringResultDAO.save(scoringResultEntity); 27 | 28 | } 29 | 30 | @Override 31 | public ScoringResultAggregate findByApplicationNumber(ApplicationNumber applicationNumber) { 32 | ScoringResultEntity scoringResultEntity = scoringResultDAO.findByApplicationNumber(applicationNumber.toString()); 33 | if(scoringResultEntity != null) { 34 | return new ScoringResultAggregate.Builder(applicationNumber) 35 | .agencyScoring(scoringResultEntity.getDetailedScoringResults().getAgencyScoringResult()) 36 | .applicantScoring(scoringResultEntity.getDetailedScoringResults().getApplicantScoringResult()) 37 | .financialSituationScoring(scoringResultEntity.getDetailedScoringResults().getFinancialSituationScoringResult()) 38 | .noGoCriteria(scoringResultEntity.getDetailedScoringResults().isNoGoCriteriaPresent()) 39 | .build(); 40 | } else { 41 | return null; 42 | } 43 | 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /assets/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.1.6.RELEASE 9 | 10 | 11 | com.mploed.dddwithspring 12 | assets 13 | 0.0.1-SNAPSHOT 14 | assets 15 | Web Assets for the DDD with Spring Example 16 | 17 | 18 | 1.8 19 | 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-web 25 | 26 | 27 | org.springframework.boot 28 | spring-boot-starter-websocket 29 | 30 | 31 | org.webjars 32 | webjars-locator-core 33 | 34 | 35 | org.webjars 36 | sockjs-client 37 | 1.0.2 38 | 39 | 40 | org.webjars 41 | stomp-websocket 42 | 2.3.3 43 | 44 | 45 | org.webjars 46 | bootstrap 47 | 3.3.7 48 | 49 | 50 | org.webjars 51 | jquery 52 | 3.1.0 53 | 54 | 55 | 56 | org.springframework.boot 57 | spring-boot-starter-test 58 | test 59 | 60 | 61 | 62 | 63 | 64 | 65 | org.springframework.boot 66 | spring-boot-maven-plugin 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /scoring/adapters-input/src/main/java/com/mploed/dddwithspring/scoring/incoming/household/EarningCapacity.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.incoming.household; 2 | 3 | import java.io.Serializable; 4 | 5 | public class EarningCapacity implements Serializable { 6 | private int salaryFirstApplicant; 7 | private int salarySecondApplicant; 8 | private int rentalIncomeFinancedProperty; 9 | private int rentalIncomeOtherProperties; 10 | private int furtherIncome; 11 | private int childBenefit; 12 | private int assetsOnBankAccounts; 13 | private int assetsOther; 14 | 15 | public int getSalaryFirstApplicant() { 16 | return salaryFirstApplicant; 17 | } 18 | 19 | public void setSalaryFirstApplicant(int salaryFirstApplicant) { 20 | this.salaryFirstApplicant = salaryFirstApplicant; 21 | } 22 | 23 | public int getSalarySecondApplicant() { 24 | return salarySecondApplicant; 25 | } 26 | 27 | public void setSalarySecondApplicant(int salarySecondApplicant) { 28 | this.salarySecondApplicant = salarySecondApplicant; 29 | } 30 | 31 | public int getRentalIncomeFinancedProperty() { 32 | return rentalIncomeFinancedProperty; 33 | } 34 | 35 | public void setRentalIncomeFinancedProperty(int rentalIncomeFinancedProperty) { 36 | this.rentalIncomeFinancedProperty = rentalIncomeFinancedProperty; 37 | } 38 | 39 | public int getRentalIncomeOtherProperties() { 40 | return rentalIncomeOtherProperties; 41 | } 42 | 43 | public void setRentalIncomeOtherProperties(int rentalIncomeOtherProperties) { 44 | this.rentalIncomeOtherProperties = rentalIncomeOtherProperties; 45 | } 46 | 47 | public int getFurtherIncome() { 48 | return furtherIncome; 49 | } 50 | 51 | public void setFurtherIncome(int furtherIncome) { 52 | this.furtherIncome = furtherIncome; 53 | } 54 | 55 | public int getChildBenefit() { 56 | return childBenefit; 57 | } 58 | 59 | public void setChildBenefit(int childBenefit) { 60 | this.childBenefit = childBenefit; 61 | } 62 | 63 | public int getAssetsOnBankAccounts() { 64 | return assetsOnBankAccounts; 65 | } 66 | 67 | public void setAssetsOnBankAccounts(int assetsOnBankAccounts) { 68 | this.assetsOnBankAccounts = assetsOnBankAccounts; 69 | } 70 | 71 | public int getAssetsOther() { 72 | return assetsOther; 73 | } 74 | 75 | public void setAssetsOther(int assetsOther) { 76 | this.assetsOther = assetsOther; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /scoring/adapters-input/src/main/java/com/mploed/dddwithspring/scoring/incoming/financing/Financing.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.incoming.financing; 2 | 3 | 4 | import java.io.Serializable; 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | public class Financing implements Serializable { 9 | private Long databaseId; 10 | 11 | private String applicationNumber; 12 | 13 | private int financingNeeds; 14 | 15 | private OwnResources ownResources; 16 | 17 | private PurchaseCosts purchaseCosts; 18 | 19 | private List loans; 20 | 21 | public Financing(String applicationNumber) { 22 | this.applicationNumber = applicationNumber; 23 | this.ownResources = new OwnResources(); 24 | this.purchaseCosts = new PurchaseCosts(); 25 | this.loans = new ArrayList(4); 26 | loans.add(new Loan()); 27 | loans.add(new Loan()); 28 | loans.add(new Loan()); 29 | loans.add(new Loan()); 30 | } 31 | 32 | public Financing() { 33 | this.ownResources = new OwnResources(); 34 | this.purchaseCosts = new PurchaseCosts(); 35 | this.loans = new ArrayList(4); 36 | loans.add(new Loan()); 37 | loans.add(new Loan()); 38 | loans.add(new Loan()); 39 | loans.add(new Loan()); 40 | } 41 | 42 | public Long getDatabaseId() { 43 | return databaseId; 44 | } 45 | 46 | public void setDatabaseId(Long databaseId) { 47 | this.databaseId = databaseId; 48 | } 49 | 50 | public void setApplicationNumber(String applicationNumber) { 51 | this.applicationNumber = applicationNumber; 52 | } 53 | 54 | public String getApplicationNumber() { 55 | return applicationNumber; 56 | } 57 | 58 | public int getFinancingNeeds() { 59 | return financingNeeds; 60 | } 61 | 62 | public void setFinancingNeeds(int financingNeeds) { 63 | this.financingNeeds = financingNeeds; 64 | } 65 | 66 | public OwnResources getOwnResources() { 67 | return ownResources; 68 | } 69 | 70 | public void setOwnResources(OwnResources ownResources) { 71 | this.ownResources = ownResources; 72 | } 73 | 74 | public PurchaseCosts getPurchaseCosts() { 75 | return purchaseCosts; 76 | } 77 | 78 | public void setPurchaseCosts(PurchaseCosts purchaseCosts) { 79 | this.purchaseCosts = purchaseCosts; 80 | } 81 | 82 | public List getLoans() { 83 | return loans; 84 | } 85 | 86 | public void setLoans(List loans) { 87 | this.loans = loans; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /credit-sales-funnel/src/main/java/com/mploed/dddwithspring/creditsalesfunnel/event/CreditApplicationSubmittedEvent.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.creditsalesfunnel.event; 2 | 3 | import com.mploed.dddwithspring.creditsalesfunnel.model.applicant.Applicant; 4 | import com.mploed.dddwithspring.creditsalesfunnel.model.financing.Financing; 5 | import com.mploed.dddwithspring.creditsalesfunnel.model.household.Household; 6 | import com.mploed.dddwithspring.creditsalesfunnel.model.realEstate.RealEstateProperty; 7 | 8 | import java.io.Serializable; 9 | import java.util.Date; 10 | 11 | public class CreditApplicationSubmittedEvent implements Serializable { 12 | private String applicationNumber; 13 | private Date timestamp; 14 | private Applicant firstApplicant; 15 | private Applicant secondApplicant; 16 | private Household household; 17 | private RealEstateProperty realEstateProperty; 18 | private Financing financing; 19 | 20 | 21 | public CreditApplicationSubmittedEvent() { 22 | this.timestamp = new Date(); 23 | } 24 | 25 | public String getApplicationNumber() { 26 | return applicationNumber; 27 | } 28 | 29 | public void setApplicationNumber(String applicationNumber) { 30 | this.applicationNumber = applicationNumber; 31 | } 32 | 33 | public Date getTimestamp() { 34 | return timestamp; 35 | } 36 | 37 | public void setTimestamp(Date timestamp) { 38 | this.timestamp = timestamp; 39 | } 40 | 41 | public Applicant getFirstApplicant() { 42 | return firstApplicant; 43 | } 44 | 45 | public void setFirstApplicant(Applicant firstApplicant) { 46 | this.firstApplicant = firstApplicant; 47 | } 48 | 49 | public Applicant getSecondApplicant() { 50 | return secondApplicant; 51 | } 52 | 53 | public void setSecondApplicant(Applicant secondApplicant) { 54 | this.secondApplicant = secondApplicant; 55 | } 56 | 57 | public Household getHousehold() { 58 | return household; 59 | } 60 | 61 | public void setHousehold(Household household) { 62 | this.household = household; 63 | } 64 | 65 | public RealEstateProperty getRealEstateProperty() { 66 | return realEstateProperty; 67 | } 68 | 69 | public void setRealEstateProperty(RealEstateProperty realEstateProperty) { 70 | this.realEstateProperty = realEstateProperty; 71 | } 72 | 73 | public Financing getFinancing() { 74 | return financing; 75 | } 76 | 77 | public void setFinancing(Financing financing) { 78 | this.financing = financing; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /credit-sales-funnel/src/main/java/com/mploed/dddwithspring/creditsalesfunnel/model/household/EarningCapacity.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.creditsalesfunnel.model.household; 2 | 3 | import javax.persistence.Embeddable; 4 | import java.io.Serializable; 5 | 6 | @Embeddable 7 | public class EarningCapacity implements Serializable { 8 | private int salaryFirstApplicant; 9 | private int salarySecondApplicant; 10 | private int rentalIncomeFinancedProperty; 11 | private int rentalIncomeOtherProperties; 12 | private int furtherIncome; 13 | private int childBenefit; 14 | private int assetsOnBankAccounts; 15 | private int assetsOther; 16 | 17 | public int getSalaryFirstApplicant() { 18 | return salaryFirstApplicant; 19 | } 20 | 21 | public void setSalaryFirstApplicant(int salaryFirstApplicant) { 22 | this.salaryFirstApplicant = salaryFirstApplicant; 23 | } 24 | 25 | public int getSalarySecondApplicant() { 26 | return salarySecondApplicant; 27 | } 28 | 29 | public void setSalarySecondApplicant(int salarySecondApplicant) { 30 | this.salarySecondApplicant = salarySecondApplicant; 31 | } 32 | 33 | public int getRentalIncomeFinancedProperty() { 34 | return rentalIncomeFinancedProperty; 35 | } 36 | 37 | public void setRentalIncomeFinancedProperty(int rentalIncomeFinancedProperty) { 38 | this.rentalIncomeFinancedProperty = rentalIncomeFinancedProperty; 39 | } 40 | 41 | public int getRentalIncomeOtherProperties() { 42 | return rentalIncomeOtherProperties; 43 | } 44 | 45 | public void setRentalIncomeOtherProperties(int rentalIncomeOtherProperties) { 46 | this.rentalIncomeOtherProperties = rentalIncomeOtherProperties; 47 | } 48 | 49 | public int getFurtherIncome() { 50 | return furtherIncome; 51 | } 52 | 53 | public void setFurtherIncome(int furtherIncome) { 54 | this.furtherIncome = furtherIncome; 55 | } 56 | 57 | public int getChildBenefit() { 58 | return childBenefit; 59 | } 60 | 61 | public void setChildBenefit(int childBenefit) { 62 | this.childBenefit = childBenefit; 63 | } 64 | 65 | public int getAssetsOnBankAccounts() { 66 | return assetsOnBankAccounts; 67 | } 68 | 69 | public void setAssetsOnBankAccounts(int assetsOnBankAccounts) { 70 | this.assetsOnBankAccounts = assetsOnBankAccounts; 71 | } 72 | 73 | public int getAssetsOther() { 74 | return assetsOther; 75 | } 76 | 77 | public void setAssetsOther(int assetsOther) { 78 | this.assetsOther = assetsOther; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | ddd-rabbit-mq: 4 | container_name: ddd-rabbit-mq 5 | image: rabbitmq:3 6 | expose: 7 | - 5672 8 | networks: 9 | - ddd-with-spring-network 10 | logging: 11 | driver: json-file 12 | credit-agency: 13 | container_name: ddd-with-spring-creditagency 14 | build: 15 | context: credit-agency 16 | dockerfile: Dockerfile 17 | image: ddd-with-spring-creditagency:latest 18 | expose: 19 | - 9002 20 | ports: 21 | - "9002:9002" 22 | networks: 23 | - ddd-with-spring-network 24 | depends_on: 25 | - ddd-rabbit-mq 26 | links: 27 | - ddd-rabbit-mq:rabbit-mq 28 | logging: 29 | driver: json-file 30 | scoring: 31 | container_name: ddd-with-spring-scoring 32 | build: 33 | context: scoring 34 | dockerfile: Dockerfile 35 | image: ddd-with-spring-scoring:latest 36 | expose: 37 | - 9001 38 | ports: 39 | - "9001:9001" 40 | networks: 41 | - ddd-with-spring-network 42 | depends_on: 43 | - ddd-rabbit-mq 44 | - credit-agency 45 | links: 46 | - ddd-rabbit-mq:rabbit-mq 47 | - credit-agency:credit-agency 48 | logging: 49 | driver: json-file 50 | credit-sales-funnel: 51 | container_name: ddd-with-spring-creditsalesfunnel 52 | build: 53 | context: credit-sales-funnel 54 | dockerfile: Dockerfile 55 | image: ddd-with-spring-creditsalesfunnel:latest 56 | expose: 57 | - 9000 58 | ports: 59 | - "9000:9000" 60 | networks: 61 | - ddd-with-spring-network 62 | depends_on: 63 | - ddd-rabbit-mq 64 | links: 65 | - ddd-rabbit-mq:rabbit-mq 66 | logging: 67 | driver: json-file 68 | varnish: 69 | build: 70 | infrastructure_varnish 71 | links: 72 | - credit-sales-funnel 73 | - scoring 74 | depends_on: 75 | - credit-sales-funnel 76 | - scoring 77 | networks: 78 | - ddd-with-spring-network 79 | ports: 80 | - "8080:8080" 81 | networks: 82 | ddd-with-spring-network: 83 | driver: bridge -------------------------------------------------------------------------------- /scoring/adapters-output/src/main/java/com/mploed/dddwithspring/scoring/financialSituation/FinancialSituationResultJPARepository.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.financialSituation; 2 | 3 | import com.mploed.dddwithspring.scoring.ApplicationNumber; 4 | import com.mploed.dddwithspring.scoring.Money; 5 | import com.mploed.dddwithspring.scoring.appservices.repositories.FinancialSituationResultRepository; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.stereotype.Component; 8 | import org.springframework.transaction.annotation.Propagation; 9 | import org.springframework.transaction.annotation.Transactional; 10 | 11 | @Component 12 | @Transactional(propagation = Propagation.REQUIRES_NEW) 13 | public class FinancialSituationResultJPARepository implements FinancialSituationResultRepository { 14 | 15 | private FinancialSituationResultDAO dao; 16 | 17 | @Autowired 18 | public FinancialSituationResultJPARepository(FinancialSituationResultDAO dao) { 19 | this.dao = dao; 20 | } 21 | 22 | 23 | @Override 24 | public void save(FinancialSituationAggregate financialSituationAggregate) { 25 | FinancialSituationResultProjection projection = new FinancialSituationResultProjection(); 26 | projection.setApplicationNumber(financialSituationAggregate.rootEntity.applicationNumber.toString()); 27 | projection.setIncomingOther(financialSituationAggregate.rootEntity.incomings.otherIncome.getAmount()); 28 | projection.setIncomingSalary(financialSituationAggregate.rootEntity.incomings.salary.getAmount()); 29 | projection.setOutgoingCostOfLiving(financialSituationAggregate.rootEntity.outgoings.costOfLiving.getAmount()); 30 | projection.setOutgoingRent(financialSituationAggregate.rootEntity.outgoings.rent.getAmount()); 31 | dao.save(projection); 32 | } 33 | 34 | @Override 35 | public FinancialSituationAggregate retrieve(ApplicationNumber applicationNumber) { 36 | FinancialSituationResultProjection projection = dao.findByApplicationNumber(applicationNumber.toString()); 37 | if(projection != null) { 38 | return new FinancialSituationAggregate.FinancialSituationBuilder(new ApplicationNumber(projection.getApplicationNumber())) 39 | .costOfLiving(new Money(projection.getOutgoingCostOfLiving())) 40 | .otherIncome(new Money(projection.getIncomingOther())) 41 | .rent(new Money(projection.getOutgoingRent())) 42 | .salary(new Money(projection.getIncomingSalary())) 43 | .build(); 44 | } else { 45 | return null; 46 | } 47 | 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /credit-sales-funnel/src/main/java/com/mploed/dddwithspring/creditsalesfunnel/model/household/MonthlyExpenses.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.creditsalesfunnel.model.household; 2 | 3 | import com.mploed.dddwithspring.creditsalesfunnel.model.validation.ApplicationSubmissionGroup; 4 | 5 | import javax.persistence.Embeddable; 6 | import javax.validation.constraints.Min; 7 | import java.io.Serializable; 8 | 9 | @Embeddable 10 | public class MonthlyExpenses implements Serializable { 11 | private int healthInsuranceFirstApplicant; 12 | private int healthInsuranceSecondApplicant; 13 | private int otherLoansRemainderOfDebt; 14 | private int otherLoansMonthlyRepayments; 15 | @Min(value = 1, groups = ApplicationSubmissionGroup.class) 16 | private int costOfLiving; 17 | private int rent; 18 | private boolean rentNotApplicableInFuture; 19 | 20 | public int getHealthInsuranceFirstApplicant() { 21 | return healthInsuranceFirstApplicant; 22 | } 23 | 24 | public void setHealthInsuranceFirstApplicant(int healthInsuranceFirstApplicant) { 25 | this.healthInsuranceFirstApplicant = healthInsuranceFirstApplicant; 26 | } 27 | 28 | public int getHealthInsuranceSecondApplicant() { 29 | return healthInsuranceSecondApplicant; 30 | } 31 | 32 | public void setHealthInsuranceSecondApplicant(int healthInsuranceSecondApplicant) { 33 | this.healthInsuranceSecondApplicant = healthInsuranceSecondApplicant; 34 | } 35 | 36 | public int getOtherLoansRemainderOfDebt() { 37 | return otherLoansRemainderOfDebt; 38 | } 39 | 40 | public void setOtherLoansRemainderOfDebt(int otherLoansRemainderOfDebt) { 41 | this.otherLoansRemainderOfDebt = otherLoansRemainderOfDebt; 42 | } 43 | 44 | public int getOtherLoansMonthlyRepayments() { 45 | return otherLoansMonthlyRepayments; 46 | } 47 | 48 | public void setOtherLoansMonthlyRepayments(int otherLoansMonthlyRepayments) { 49 | this.otherLoansMonthlyRepayments = otherLoansMonthlyRepayments; 50 | } 51 | 52 | public int getCostOfLiving() { 53 | return costOfLiving; 54 | } 55 | 56 | public void setCostOfLiving(int costOfLiving) { 57 | this.costOfLiving = costOfLiving; 58 | } 59 | 60 | public int getRent() { 61 | return rent; 62 | } 63 | 64 | public void setRent(int rent) { 65 | this.rent = rent; 66 | } 67 | 68 | public boolean isRentNotApplicableInFuture() { 69 | return rentNotApplicableInFuture; 70 | } 71 | 72 | public void setRentNotApplicableInFuture(boolean rentNotApplicableInFuture) { 73 | this.rentNotApplicableInFuture = rentNotApplicableInFuture; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /scoring/application-services/src/main/java/com/mploed/dddwithspring/scoring/appservices/dto/CreditApplication.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.appservices.dto; 2 | 3 | import com.mploed.dddwithspring.scoring.ApplicationNumber; 4 | import com.mploed.dddwithspring.scoring.Money; 5 | 6 | public class CreditApplication { 7 | private ApplicationNumber applicationNumber; 8 | private Applicant applicant; 9 | private FinancialSituation financialSituation; 10 | 11 | public ApplicationNumber getApplicationNumber() { 12 | return applicationNumber; 13 | } 14 | 15 | public FinancialSituation getFinancialSituation() { 16 | return financialSituation; 17 | } 18 | 19 | public Applicant getApplicant() { 20 | return applicant; 21 | } 22 | 23 | private CreditApplication(CreditApplication.CreditApplicationBuilder builder) { 24 | this.applicationNumber = builder.applicationNumber; 25 | this.applicant = builder.applicant; 26 | this.financialSituation = builder.financialSituation; 27 | } 28 | 29 | public static class CreditApplicationBuilder { 30 | private final ApplicationNumber applicationNumber; 31 | private Applicant applicant; 32 | private FinancialSituation financialSituation; 33 | 34 | public CreditApplicationBuilder(ApplicationNumber applicationNumber) { 35 | this.applicationNumber = applicationNumber; 36 | } 37 | 38 | public CreditApplication.CreditApplicationBuilder withFinancialSituation(Money costOfLiving, 39 | Money furtherIncome, 40 | Money rent, 41 | Money salary) { 42 | this.financialSituation = new FinancialSituation(costOfLiving, furtherIncome, rent, salary); 43 | return this; 44 | 45 | } 46 | public CreditApplication.CreditApplicationBuilder withApplicant(String firstName, 47 | String lastName, 48 | String street, 49 | String postCode, 50 | String city) { 51 | this.applicant = new Applicant(firstName, lastName, street, postCode, city); 52 | return this; 53 | } 54 | 55 | 56 | public CreditApplication build() { 57 | return new CreditApplication(this); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /scoring/adapters-input/src/main/java/com/mploed/dddwithspring/scoring/messaging/IncomingMessageListener.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.messaging; 2 | 3 | import com.mploed.dddwithspring.scoring.ApplicationNumber; 4 | import com.mploed.dddwithspring.scoring.Money; 5 | import com.mploed.dddwithspring.scoring.appservices.ScoringApplicationService; 6 | import com.mploed.dddwithspring.scoring.appservices.dto.CreditApplication; 7 | import com.mploed.dddwithspring.scoring.appservices.dto.FinancialSituation; 8 | import com.mploed.dddwithspring.scoring.incoming.ApplicationSubmittedEvent; 9 | import com.mploed.dddwithspring.scoring.incoming.applicant.Applicant; 10 | import com.mploed.dddwithspring.scoring.incoming.household.EarningCapacity; 11 | import com.mploed.dddwithspring.scoring.incoming.household.MonthlyExpenses; 12 | import org.springframework.cloud.stream.annotation.StreamListener; 13 | import org.springframework.messaging.handler.annotation.Payload; 14 | import org.springframework.stereotype.Component; 15 | 16 | @Component 17 | public class IncomingMessageListener { 18 | private ScoringApplicationService scoringApplicationService; 19 | 20 | public IncomingMessageListener(ScoringApplicationService scoringApplicationService) { 21 | this.scoringApplicationService = scoringApplicationService; 22 | } 23 | 24 | @StreamListener(ApplicationProcessChannels.APPLICATION_SUBMITTED) 25 | public void receiveApplicationSubmission(@Payload ApplicationSubmittedEvent applicationSubmittedEvent) { 26 | Applicant firstApplicant = applicationSubmittedEvent.getFirstApplicant(); 27 | MonthlyExpenses monthlyExpenses = applicationSubmittedEvent.getHousehold().getMonthlyExpenses(); 28 | EarningCapacity earningCapacity = applicationSubmittedEvent.getHousehold().getEarningCapacity(); 29 | CreditApplication creditApplication = new CreditApplication.CreditApplicationBuilder(new ApplicationNumber(applicationSubmittedEvent.getApplicationNumber())) 30 | .withApplicant(firstApplicant.getFirstName(), 31 | firstApplicant.getLastName(), 32 | firstApplicant.getAddress().getStreet(), 33 | firstApplicant.getAddress().getPostCode(), 34 | firstApplicant.getAddress().getCity()) 35 | .withFinancialSituation(new Money(monthlyExpenses.getCostOfLiving()), 36 | new Money(earningCapacity.getFurtherIncome()), 37 | new Money(monthlyExpenses.getRent()), 38 | new Money(earningCapacity.getSalaryFirstApplicant())) 39 | .build(); 40 | scoringApplicationService.scoreApplication(creditApplication); 41 | 42 | } 43 | 44 | 45 | } 46 | -------------------------------------------------------------------------------- /scoring/adapters-output/src/main/java/com/mploed/dddwithspring/scoring/agencyResult/AgencyResultJPARepository.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.agencyResult; 2 | 3 | import com.mploed.dddwithspring.scoring.PersonId; 4 | import com.mploed.dddwithspring.scoring.appservices.repositories.AgencyResultRepository; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.stereotype.Component; 7 | import org.springframework.transaction.annotation.Propagation; 8 | import org.springframework.transaction.annotation.Transactional; 9 | 10 | @Component 11 | @Transactional(propagation = Propagation.REQUIRES_NEW) 12 | public class AgencyResultJPARepository implements AgencyResultRepository { 13 | 14 | private AgencyResultDAO dao; 15 | 16 | @Autowired 17 | public AgencyResultJPARepository(AgencyResultDAO dao) { 18 | this.dao = dao; 19 | } 20 | 21 | @Override 22 | public void save(AgencyResultAggregate agencyResultAggregate) { 23 | AgencyResultProjection agencyResultProjection = new AgencyResultProjection(); 24 | agencyResultProjection.setPersonId(agencyResultAggregate.getAgencyResultRootEntity().id.toString()); 25 | agencyResultProjection.setPoints(agencyResultAggregate.getAgencyResultRootEntity().points); 26 | agencyResultAggregate.getAgencyResultRootEntity().getKoCriteria().forEach((KoCriteria element) -> 27 | agencyResultProjection.addKoCriteria(new AgencyMessage(element.getKey(), element.getMessageText()))); 28 | 29 | agencyResultAggregate.getAgencyResultRootEntity().getWarningMessages().forEach((WarningMessage element) -> 30 | agencyResultProjection.addWarning(new AgencyMessage(element.getKey(), element.getMessageText()))); 31 | dao.save(agencyResultProjection); 32 | 33 | } 34 | 35 | @Override 36 | public AgencyResultAggregate retrieve(PersonId personId) { 37 | AgencyResultProjection agencyResultProjection = dao.findByPersonId(personId.toString()); 38 | if(agencyResultProjection != null) { 39 | AgencyResultAggregate.AgencyResultBuilder agencyResultBuilder = new AgencyResultAggregate.AgencyResultBuilder().personId(new PersonId(agencyResultProjection.getPersonId())) 40 | .withPoints(agencyResultProjection.getPoints()); 41 | agencyResultProjection.getKoCriteria().forEach((AgencyMessage message) -> 42 | agencyResultBuilder.withKoCriteria(message.getKey(), message.getMessage())); 43 | agencyResultProjection.getWarnings().forEach((AgencyMessage message) -> 44 | agencyResultBuilder.withWarning(message.getKey(), message.getMessage())); 45 | return agencyResultBuilder.build(); 46 | } else { 47 | return null; 48 | } 49 | 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /credit-agency/src/main/java/com/mploed/dddwithspring/creditagency/events/incoming/applicant/Applicant.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.creditagency.events.incoming.applicant; 2 | 3 | import java.io.Serializable; 4 | import java.util.Date; 5 | 6 | public class Applicant implements Serializable { 7 | 8 | 9 | private String firstName; 10 | 11 | private String lastName; 12 | 13 | private Address address; 14 | 15 | private MaritalStatus maritalStatus; 16 | 17 | private Business business; 18 | 19 | private Employment employment; 20 | 21 | private Date employedSince; 22 | 23 | private Date birthday; 24 | 25 | 26 | public Applicant() { 27 | this.address = new Address(); 28 | } 29 | 30 | public String getFirstName() { 31 | return firstName; 32 | } 33 | 34 | public void setFirstName(String firstName) { 35 | this.firstName = firstName; 36 | } 37 | 38 | public String getLastName() { 39 | return lastName; 40 | } 41 | 42 | public void setLastName(String lastName) { 43 | this.lastName = lastName; 44 | } 45 | 46 | public Address getAddress() { 47 | return address; 48 | } 49 | 50 | public void setAddress(Address address) { 51 | this.address = address; 52 | } 53 | 54 | public MaritalStatus getMaritalStatus() { 55 | return maritalStatus; 56 | } 57 | 58 | public void setMaritalStatus(MaritalStatus maritalStatus) { 59 | this.maritalStatus = maritalStatus; 60 | } 61 | 62 | public Business getBusiness() { 63 | return business; 64 | } 65 | 66 | public void setBusiness(Business business) { 67 | this.business = business; 68 | } 69 | 70 | public Employment getEmployment() { 71 | return employment; 72 | } 73 | 74 | public void setEmployment(Employment employment) { 75 | this.employment = employment; 76 | } 77 | 78 | public Date getEmployedSince() { 79 | return employedSince; 80 | } 81 | 82 | public void setEmployedSince(Date employedSince) { 83 | this.employedSince = employedSince; 84 | } 85 | 86 | public Date getBirthday() { 87 | return birthday; 88 | } 89 | 90 | public void setBirthday(Date birthday) { 91 | this.birthday = birthday; 92 | } 93 | 94 | @Override 95 | public String toString() { 96 | return "Applicant{" + 97 | "firstName='" + firstName + '\'' + 98 | ", lastName='" + lastName + '\'' + 99 | ", address=" + address + 100 | ", maritalStatus=" + maritalStatus + 101 | ", business=" + business + 102 | ", employment=" + employment + 103 | ", employedSince=" + employedSince + 104 | ", birthday=" + birthday + 105 | '}'; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /scoring/aggregates/src/main/java/com/mploed/dddwithspring/scoring/financialSituation/FinancialSituationAggregate.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.financialSituation; 2 | 3 | import com.mploed.dddwithspring.scoring.ApplicationNumber; 4 | import com.mploed.dddwithspring.scoring.Money; 5 | import com.mploed.dddwithspring.scoring.microarchitecture.Aggregate; 6 | import com.mploed.dddwithspring.scoring.microarchitecture.AggregateBuilder; 7 | 8 | @Aggregate 9 | public class FinancialSituationAggregate { 10 | FinancialSituationRootEntity rootEntity; 11 | 12 | private FinancialSituationAggregate(FinancialSituationBuilder builder) { 13 | Incomings incomings = new Incomings(builder.salary, builder.otherIncome); 14 | Outgoings outgoings = new Outgoings(builder.rent, builder.costOfLiving); 15 | this.rootEntity = new FinancialSituationRootEntity(builder.applicationNumber, incomings, outgoings); 16 | } 17 | 18 | public int calculateScoringPoints() { 19 | Money monthlyBalance = rootEntity.sum(); 20 | if(monthlyBalance.isGreaterThan(new Money(2000))) { 21 | return 35; 22 | } else if(monthlyBalance.isGreaterThan(new Money(1000))) { 23 | return 20; 24 | } else if(monthlyBalance.isGreaterThan(new Money(750))) { 25 | return 15; 26 | } else if(monthlyBalance.isGreaterThan(new Money(500))) { 27 | return 10; 28 | } else if (monthlyBalance.isGreaterThan(new Money(250))) { 29 | return 5; 30 | } else if( monthlyBalance.isGreaterThan(new Money(0))) { 31 | return 0; 32 | } else { 33 | return -10; 34 | } 35 | } 36 | 37 | public ApplicationNumber getApplicationNumber() { 38 | return rootEntity.applicationNumber; 39 | } 40 | 41 | @AggregateBuilder 42 | public static class FinancialSituationBuilder { 43 | private final ApplicationNumber applicationNumber; 44 | private Money rent; 45 | private Money costOfLiving; 46 | private Money salary; 47 | private Money otherIncome; 48 | 49 | public FinancialSituationBuilder(ApplicationNumber applicationNumber) { 50 | this.applicationNumber = applicationNumber; 51 | } 52 | 53 | public FinancialSituationBuilder rent(Money rent) { 54 | this.rent = rent; 55 | return this; 56 | } 57 | 58 | public FinancialSituationBuilder costOfLiving(Money costOfLiving) { 59 | this.costOfLiving = costOfLiving; 60 | return this; 61 | } 62 | 63 | public FinancialSituationBuilder salary(Money salary) { 64 | this.salary = salary; 65 | return this; 66 | } 67 | 68 | public FinancialSituationBuilder otherIncome(Money otherIncome) { 69 | this.otherIncome = otherIncome; 70 | return this; 71 | } 72 | 73 | public FinancialSituationAggregate build() { 74 | return new FinancialSituationAggregate(this); 75 | } 76 | 77 | 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /scoring/adapters-input/src/main/java/com/mploed/dddwithspring/scoring/incoming/household/Household.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.incoming.household; 2 | 3 | import java.io.Serializable; 4 | import java.util.Objects; 5 | 6 | public class Household implements Serializable { 7 | private Long databaseId; 8 | 9 | private String applicationNumber; 10 | 11 | private int adultsInHousehold; 12 | private int childrenInHousehold; 13 | 14 | private String iban; 15 | 16 | private String bic; 17 | 18 | private EarningCapacity earningCapacity; 19 | 20 | private MonthlyExpenses monthlyExpenses; 21 | 22 | 23 | private Household() { 24 | } 25 | 26 | public Household(String applicationNumber) { 27 | this.earningCapacity = new EarningCapacity(); 28 | this.monthlyExpenses = new MonthlyExpenses(); 29 | this.applicationNumber = applicationNumber; 30 | } 31 | 32 | 33 | @Override 34 | public boolean equals(Object o) { 35 | if (this == o) return true; 36 | if (o == null || getClass() != o.getClass()) return false; 37 | Household household = (Household) o; 38 | return Objects.equals(applicationNumber, household.applicationNumber); 39 | } 40 | 41 | @Override 42 | public int hashCode() { 43 | 44 | return Objects.hash(applicationNumber); 45 | } 46 | 47 | public Long getDatabaseId() { 48 | return databaseId; 49 | } 50 | 51 | public void setDatabaseId(Long databaseId) { 52 | this.databaseId = databaseId; 53 | } 54 | 55 | public EarningCapacity getEarningCapacity() { 56 | return earningCapacity; 57 | } 58 | 59 | public void setEarningCapacity(EarningCapacity earningCapacity) { 60 | this.earningCapacity = earningCapacity; 61 | } 62 | 63 | public MonthlyExpenses getMonthlyExpenses() { 64 | return monthlyExpenses; 65 | } 66 | 67 | public void setMonthlyExpenses(MonthlyExpenses monthlyExpenses) { 68 | this.monthlyExpenses = monthlyExpenses; 69 | } 70 | 71 | public String getApplicationNumber() { 72 | return applicationNumber; 73 | } 74 | 75 | public int getAdultsInHousehold() { 76 | return adultsInHousehold; 77 | } 78 | 79 | public void setAdultsInHousehold(int adultsInHousehold) { 80 | this.adultsInHousehold = adultsInHousehold; 81 | } 82 | 83 | public int getChildrenInHousehold() { 84 | return childrenInHousehold; 85 | } 86 | 87 | public void setChildrenInHousehold(int childrenInHousehold) { 88 | this.childrenInHousehold = childrenInHousehold; 89 | } 90 | 91 | public String getIban() { 92 | return iban; 93 | } 94 | 95 | public void setIban(String iban) { 96 | this.iban = iban; 97 | } 98 | 99 | public String getBic() { 100 | return bic; 101 | } 102 | 103 | public void setBic(String bic) { 104 | this.bic = bic; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /scoring/adapters-output/src/main/java/com/mploed/dddwithspring/scoring/applicant/ApplicantResultJPARepository.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.applicant; 2 | 3 | import com.mploed.dddwithspring.scoring.ApplicationNumber; 4 | import com.mploed.dddwithspring.scoring.PersonId; 5 | import com.mploed.dddwithspring.scoring.appservices.repositories.ApplicantResultRepository; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.stereotype.Component; 8 | import org.springframework.transaction.annotation.Propagation; 9 | import org.springframework.transaction.annotation.Transactional; 10 | 11 | @Component 12 | @Transactional(propagation = Propagation.REQUIRES_NEW) 13 | public class ApplicantResultJPARepository implements ApplicantResultRepository { 14 | 15 | private ApplicantResultDAO dao; 16 | 17 | @Autowired 18 | public ApplicantResultJPARepository(ApplicantResultDAO dao) { 19 | this.dao = dao; 20 | } 21 | 22 | 23 | @Override 24 | public void save(ApplicantAggregate applicantAggregate) { 25 | 26 | ApplicantResultProjection projection = new ApplicantResultProjection(); 27 | projection.setApplicationNumber(applicantAggregate.getApplicationNumber().toString()); 28 | projection.setPersonId(applicantAggregate.getPersonId().toString()); 29 | projection.setBalance(applicantAggregate.getBalance().toBigDecimal()); 30 | projection.setCity(applicantAggregate.getAddress().getCity()); 31 | projection.setPostCode(applicantAggregate.getAddress().getPostCode()); 32 | projection.setStreet(applicantAggregate.getAddress().getStreet()); 33 | projection.setLastName(applicantAggregate.getLastName()); 34 | projection.setName(applicantAggregate.getName()); 35 | this.dao.save(projection); 36 | } 37 | 38 | @Override 39 | public ApplicantAggregate retrieve(ApplicationNumber applicationNumber) { 40 | ApplicantResultProjection projection = dao.findByApplicationNumber(applicationNumber.toString()); 41 | if(projection != null) { 42 | return toApplicantAggregate(projection); 43 | } else { 44 | return null; 45 | } 46 | 47 | } 48 | 49 | 50 | @Override 51 | public ApplicantAggregate retrieve(PersonId personId) { 52 | ApplicantResultProjection projection = dao.findByPersonId(personId.toString()); 53 | if(projection != null) { 54 | return toApplicantAggregate(projection); 55 | } else { 56 | return null; 57 | } 58 | } 59 | 60 | private ApplicantAggregate toApplicantAggregate(ApplicantResultProjection projection) { 61 | return new ApplicantAggregate.ApplicantAggregateBuilder(new ApplicationNumber(projection.getApplicationNumber())) 62 | .accountBalance(projection.getBalance()) 63 | .city(projection.getCity()) 64 | .postCode(projection.getPostCode()) 65 | .street(projection.getStreet()) 66 | .firstName(projection.getName()) 67 | .lastName(projection.getLastName()) 68 | .build(); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /scoring/sharedmodel/src/main/java/com/mploed/dddwithspring/scoring/PersonId.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring; 2 | 3 | import java.security.MessageDigest; 4 | import java.security.NoSuchAlgorithmException; 5 | import java.util.Objects; 6 | 7 | public class PersonId { 8 | private String personId; 9 | 10 | public PersonId(String personId) { 11 | this.personId = personId; 12 | } 13 | 14 | @Override 15 | public String toString() { 16 | return personId; 17 | } 18 | 19 | private PersonId(PersonIdBuilder builder) { 20 | try { 21 | MessageDigest messageDigest = MessageDigest.getInstance("SHA-256"); 22 | byte[] shaHash = messageDigest.digest(builder.toString().getBytes()); 23 | this.personId = convertByteArrayToHexString(shaHash); 24 | } catch (NoSuchAlgorithmException e) { 25 | e.printStackTrace(); 26 | } 27 | } 28 | 29 | private static String convertByteArrayToHexString(byte[] arrayBytes) { 30 | StringBuffer stringBuffer = new StringBuffer(); 31 | for (int i = 0; i < arrayBytes.length; i++) { 32 | stringBuffer.append(Integer.toString((arrayBytes[i] & 0xff) + 0x100, 16) 33 | .substring(1)); 34 | } 35 | return stringBuffer.toString(); 36 | } 37 | 38 | public static class PersonIdBuilder { 39 | private final String firstName; 40 | private final String lastName; 41 | private String street; 42 | private String postCode; 43 | private String city; 44 | 45 | public PersonIdBuilder(String firstName, String lastName) { 46 | this.firstName = firstName; 47 | this.lastName = lastName; 48 | } 49 | 50 | public PersonIdBuilder street(String street) { 51 | this.street = street; 52 | return this; 53 | } 54 | 55 | public PersonIdBuilder postCode(String postCode) { 56 | this.postCode = postCode; 57 | return this; 58 | } 59 | 60 | public PersonIdBuilder city(String city) { 61 | this.city = city; 62 | return this; 63 | } 64 | 65 | @Override 66 | public String toString() { 67 | return "PersonId{" + 68 | "firstName='" + firstName + '\'' + 69 | ", lastName='" + lastName + '\'' + 70 | ", street='" + street + '\'' + 71 | ", postCode='" + postCode + '\'' + 72 | ", city='" + city + '\'' + 73 | '}'; 74 | } 75 | 76 | public PersonId build() { 77 | return new PersonId(this); 78 | } 79 | 80 | @Override 81 | public boolean equals(Object o) { 82 | if (this == o) return true; 83 | if (o == null || getClass() != o.getClass()) return false; 84 | PersonIdBuilder that = (PersonIdBuilder) o; 85 | return Objects.equals(firstName, that.firstName) && 86 | Objects.equals(lastName, that.lastName) && 87 | Objects.equals(street, that.street) && 88 | Objects.equals(postCode, that.postCode) && 89 | Objects.equals(city, that.city); 90 | } 91 | 92 | @Override 93 | public int hashCode() { 94 | return Objects.hash(firstName, lastName, street, postCode, city); 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /scoring/application-services/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.0.0.RELEASE 9 | 10 | 11 | 12 | 4.0.0 13 | 14 | com.mploed.dddwithspring.scoring 15 | application-services 16 | jar 17 | 0.0.1-SNAPSHOT 18 | 19 | 20 | 21 | UTF-8 22 | UTF-8 23 | 1.8 24 | Finchley.M9 25 | 26 | 27 | 28 | 29 | com.mploed.dddwithspring.scoring 30 | aggregates 31 | 0.0.1-SNAPSHOT 32 | 33 | 34 | com.mploed.dddwithspring.scoring 35 | sharedmodel 36 | 0.0.1-SNAPSHOT 37 | 38 | 39 | org.springframework.boot 40 | spring-boot-starter-actuator 41 | 42 | 43 | 44 | org.springframework.boot 45 | spring-boot-devtools 46 | runtime 47 | 48 | 49 | org.springframework.boot 50 | spring-boot-starter-test 51 | test 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | org.springframework.cloud 60 | spring-cloud-dependencies 61 | ${spring-cloud.version} 62 | pom 63 | import 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | spring-milestones 72 | Spring Milestones 73 | https://repo.spring.io/milestone 74 | 75 | false 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /scoring/aggregates/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 4.0.0 7 | 8 | com.mploed.dddwithspring.scoring 9 | aggregates 10 | 0.0.1-SNAPSHOT 11 | jar 12 | 13 | 14 | UTF-8 15 | 1.8 16 | 1.8 17 | 18 | 19 | 20 | 21 | com.mploed.dddwithspring.scoring 22 | sharedmodel 23 | 0.0.1-SNAPSHOT 24 | 25 | 26 | com.mploed.dddwithspring.scoring 27 | microarchitecture 28 | 0.0.1-SNAPSHOT 29 | 30 | 31 | com.tngtech.archunit 32 | archunit-junit4 33 | 0.12.0 34 | test 35 | 36 | 37 | junit 38 | junit 39 | 4.13.1 40 | test 41 | 42 | 43 | 44 | 45 | 46 | 47 | com.buschmais.jqassistant 48 | jqassistant-maven-plugin 49 | 1.4.0 50 | 51 | 52 | 53 | scan 54 | analyze 55 | 56 | 57 | MINOR 58 | MAJOR 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | com.buschmais.jqassistant 70 | jqassistant-maven-plugin 71 | 72 | 73 | 74 | report 75 | 76 | 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /scoring/aggregates/src/test/java/com/mploed/dddwithspring/scoring/agencyResult/AgencyResultTest.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.agencyResult; 2 | 3 | import org.junit.Test; 4 | 5 | import static junit.framework.TestCase.assertTrue; 6 | import static org.junit.Assert.assertEquals; 7 | import static org.junit.Assert.assertFalse; 8 | 9 | public class AgencyResultTest { 10 | 11 | @Test 12 | public void testScoring0Ko0Warn95Points() { 13 | AgencyResultAggregate agencyResultAggregate = new AgencyResultAggregate.AgencyResultBuilder() 14 | .forPerson("Michael", "Plöd", "Kreuzstrasse 16", "80331", "München") 15 | .withPoints(95) 16 | .build(); 17 | 18 | 19 | assertTrue(agencyResultAggregate.isAcceptable()); 20 | assertEquals(20, agencyResultAggregate.calculateScoringPoints()); 21 | } 22 | 23 | @Test 24 | public void testScoring0Ko6Warn95Points() { 25 | AgencyResultAggregate agencyResultAggregate = new AgencyResultAggregate.AgencyResultBuilder() 26 | .forPerson("Michael", "Plöd", "Kreuzstrasse 16", "80331", "München") 27 | .withPoints(95) 28 | .withWarning("1", "---") 29 | .withWarning("2", "---") 30 | .withWarning("3", "---") 31 | .withWarning("4", "---") 32 | .withWarning("5", "---") 33 | .withWarning("6", "---") 34 | .build(); 35 | assertFalse(agencyResultAggregate.isAcceptable()); 36 | assertEquals(15, agencyResultAggregate.calculateScoringPoints()); 37 | } 38 | 39 | @Test 40 | public void testScoring0Ko0Warn83Points() { 41 | AgencyResultAggregate agencyResultAggregate = new AgencyResultAggregate.AgencyResultBuilder() 42 | .forPerson("Michael", "Plöd", "Kreuzstrasse 16", "80331", "München") 43 | .withPoints(83) 44 | .build(); 45 | assertTrue(agencyResultAggregate.isAcceptable()); 46 | assertEquals(10, agencyResultAggregate.calculateScoringPoints()); 47 | } 48 | 49 | @Test 50 | public void testScoring0Ko0Warn90Points() { 51 | AgencyResultAggregate agencyResultAggregate = new AgencyResultAggregate.AgencyResultBuilder() 52 | .forPerson("Michael", "Plöd", "Kreuzstrasse 16", "80331", "München") 53 | .withPoints(90) 54 | .build(); 55 | assertTrue(agencyResultAggregate.isAcceptable()); 56 | assertEquals(15, agencyResultAggregate.calculateScoringPoints()); 57 | } 58 | 59 | @Test 60 | public void testScoring0Ko1Warn90Points() { 61 | AgencyResultAggregate agencyResultAggregate = new AgencyResultAggregate.AgencyResultBuilder() 62 | .forPerson("Michael", "Plöd", "Kreuzstrasse 16", "80331", "München") 63 | .withWarning("00", "has only money for cheap pug food") 64 | .withPoints(90) 65 | .build(); 66 | assertTrue(agencyResultAggregate.isAcceptable()); 67 | assertEquals(10, agencyResultAggregate.calculateScoringPoints()); 68 | } 69 | 70 | @Test 71 | public void testScoring1Ko0Warn90Points() { 72 | AgencyResultAggregate agencyResultAggregate = new AgencyResultAggregate.AgencyResultBuilder() 73 | .forPerson("Michael", "Plöd", "Kreuzstrasse 16", "80331", "München") 74 | .withKoCriteria("200", "is bankrupt") 75 | .withPoints(90) 76 | .build(); 77 | assertFalse(agencyResultAggregate.isAcceptable()); 78 | assertEquals(0, agencyResultAggregate.calculateScoringPoints()); 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /credit-sales-funnel/src/main/java/com/mploed/dddwithspring/creditsalesfunnel/model/financing/Financing.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.creditsalesfunnel.model.financing; 2 | 3 | import com.mploed.dddwithspring.creditsalesfunnel.model.validation.ApplicationSubmissionGroup; 4 | import org.hibernate.annotations.IndexColumn; 5 | 6 | import javax.persistence.*; 7 | import javax.validation.Valid; 8 | import javax.validation.constraints.Min; 9 | import javax.validation.constraints.NotEmpty; 10 | import javax.validation.constraints.NotNull; 11 | import java.io.Serializable; 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | 15 | @Entity 16 | public class Financing implements Serializable { 17 | @Id 18 | @GeneratedValue(strategy = GenerationType.TABLE) 19 | private Long databaseId; 20 | 21 | @NotNull(groups = ApplicationSubmissionGroup.class) 22 | @NotEmpty(groups = ApplicationSubmissionGroup.class) 23 | private String applicationNumber; 24 | 25 | @Min(1000) 26 | private int financingNeeds; 27 | 28 | @Embedded 29 | @Valid 30 | @NotNull(groups = ApplicationSubmissionGroup.class) 31 | private OwnResources ownResources; 32 | 33 | @Embedded 34 | @Valid 35 | @NotNull(groups = ApplicationSubmissionGroup.class) 36 | private PurchaseCosts purchaseCosts; 37 | 38 | @OneToMany(cascade = CascadeType.ALL) 39 | private List loans; 40 | 41 | public Financing(String applicationNumber) { 42 | this.applicationNumber = applicationNumber; 43 | this.ownResources = new OwnResources(); 44 | this.purchaseCosts = new PurchaseCosts(); 45 | this.loans = new ArrayList(4); 46 | loans.add(new Loan()); 47 | loans.add(new Loan()); 48 | loans.add(new Loan()); 49 | loans.add(new Loan()); 50 | } 51 | 52 | public Financing() { 53 | this.ownResources = new OwnResources(); 54 | this.purchaseCosts = new PurchaseCosts(); 55 | this.loans = new ArrayList(4); 56 | loans.add(new Loan()); 57 | loans.add(new Loan()); 58 | loans.add(new Loan()); 59 | loans.add(new Loan()); 60 | } 61 | 62 | public Long getDatabaseId() { 63 | return databaseId; 64 | } 65 | 66 | public void setDatabaseId(Long databaseId) { 67 | this.databaseId = databaseId; 68 | } 69 | 70 | public void setApplicationNumber(String applicationNumber) { 71 | this.applicationNumber = applicationNumber; 72 | } 73 | 74 | public String getApplicationNumber() { 75 | return applicationNumber; 76 | } 77 | 78 | public int getFinancingNeeds() { 79 | return financingNeeds; 80 | } 81 | 82 | public void setFinancingNeeds(int financingNeeds) { 83 | this.financingNeeds = financingNeeds; 84 | } 85 | 86 | public OwnResources getOwnResources() { 87 | return ownResources; 88 | } 89 | 90 | public void setOwnResources(OwnResources ownResources) { 91 | this.ownResources = ownResources; 92 | } 93 | 94 | public PurchaseCosts getPurchaseCosts() { 95 | return purchaseCosts; 96 | } 97 | 98 | public void setPurchaseCosts(PurchaseCosts purchaseCosts) { 99 | this.purchaseCosts = purchaseCosts; 100 | } 101 | 102 | public List getLoans() { 103 | return loans; 104 | } 105 | 106 | public void setLoans(List loans) { 107 | this.loans = loans; 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /credit-agency/src/main/java/com/mploed/dddwithspring/creditagency/web/PersonRatingAtomFeedView.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.creditagency.web; 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper; 4 | import com.mploed.dddwithspring.creditagency.model.PersonRating; 5 | import com.mploed.dddwithspring.creditagency.repository.PersonRatingRepository; 6 | import com.rometools.rome.feed.atom.*; 7 | import com.rometools.rome.feed.synd.SyndPerson; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.data.domain.Sort; 10 | import org.springframework.web.servlet.view.feed.AbstractAtomFeedView; 11 | 12 | import javax.servlet.http.HttpServletRequest; 13 | import javax.servlet.http.HttpServletResponse; 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | import java.util.Map; 17 | 18 | public class PersonRatingAtomFeedView extends AbstractAtomFeedView { 19 | private PersonRatingRepository personRatingRepository; 20 | 21 | public PersonRatingAtomFeedView(PersonRatingRepository personRatingRepository) { 22 | this.personRatingRepository = personRatingRepository; 23 | } 24 | 25 | @Override 26 | protected void buildFeedMetadata(Map model, Feed feed, HttpServletRequest request) { 27 | feed.setId("https://github.com/mploed/ddd-with-spring/credit-agency"); 28 | feed.setTitle("Credit Agency Ratings"); 29 | List alternateLinks = new ArrayList<>(); 30 | Link link = new Link(); 31 | link.setRel("self"); 32 | link.setHref(baseUrl(request) + "feed"); 33 | alternateLinks.add(link); 34 | List authors = new ArrayList(); 35 | Person person = new Person(); 36 | person.setName("Big Pug Bank"); 37 | authors.add(person); 38 | feed.setAuthors(authors); 39 | 40 | feed.setAlternateLinks(alternateLinks); 41 | feed.setUpdated(personRatingRepository.lastUpdate()); 42 | Content subtitle = new Content(); 43 | subtitle.setValue("List of all valid person ratings"); 44 | feed.setSubtitle(subtitle); 45 | } 46 | 47 | private String baseUrl(HttpServletRequest request) { 48 | return String.format("%s://%s:%d%s/", request.getScheme(), request.getServerName(), request.getServerPort(), 49 | request.getContextPath()); 50 | } 51 | 52 | @Override 53 | protected List buildFeedEntries(Map model, HttpServletRequest request, 54 | HttpServletResponse response) throws Exception { 55 | 56 | List entries = new ArrayList(); 57 | ObjectMapper mapper = new ObjectMapper(); 58 | 59 | for (PersonRating personRating : personRatingRepository.findAll(new Sort(Sort.Direction.DESC, "lastUpdated"))) { 60 | Entry entry = new Entry(); 61 | entry.setId("https://github.com/mploed/ddd-with-spring/person-rating/" + personRating.getId()); 62 | entry.setUpdated(personRating.getLastUpdated()); 63 | entry.setTitle("Person Rating " + personRating.getId()); 64 | 65 | List contents = new ArrayList(); 66 | Content content = new Content(); 67 | content.setSrc(baseUrl(request) + "rating/rest/" + personRating.getId()); 68 | content.setType("application/json"); 69 | 70 | contents.add(content); 71 | entry.setContents(contents); 72 | Content summary = new Content(); 73 | summary.setValue(mapper.writeValueAsString(personRating)); 74 | entry.setSummary(summary); 75 | entries.add(entry); 76 | } 77 | 78 | return entries; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /scoring/aggregates/src/main/java/com/mploed/dddwithspring/scoring/agencyResult/AgencyResultAggregate.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.agencyResult; 2 | 3 | 4 | 5 | 6 | import com.mploed.dddwithspring.scoring.PersonId; 7 | import com.mploed.dddwithspring.scoring.microarchitecture.Aggregate; 8 | import com.mploed.dddwithspring.scoring.microarchitecture.AggregateBuilder; 9 | 10 | import java.util.HashSet; 11 | import java.util.Set; 12 | 13 | @Aggregate 14 | public class AgencyResultAggregate { 15 | private AgencyResultRootEntity agencyResultRootEntity; 16 | 17 | AgencyResultRootEntity getAgencyResultRootEntity() { 18 | return agencyResultRootEntity; 19 | } 20 | 21 | private AgencyResultAggregate(AgencyResultBuilder builder) { 22 | this.agencyResultRootEntity = new AgencyResultRootEntity(builder.personId, builder.points); 23 | this.agencyResultRootEntity.addAllKoCriteria(builder.koCriteria); 24 | this.agencyResultRootEntity.addAllWarningMessage(builder.warningMessages); 25 | } 26 | 27 | 28 | public PersonId getPersonId() { 29 | return agencyResultRootEntity.id; 30 | } 31 | public boolean isAcceptable() { 32 | return agencyResultRootEntity.isAcceptable(); 33 | } 34 | 35 | public int calculateScoringPoints() { 36 | return agencyResultRootEntity.calculateScoringPoints(); 37 | } 38 | 39 | @AggregateBuilder 40 | public static class AgencyResultBuilder { 41 | private int points; 42 | private final Set koCriteria; 43 | private final Set warningMessages; 44 | private PersonId personId; 45 | 46 | public AgencyResultBuilder() { 47 | this.koCriteria = new HashSet(); 48 | this.warningMessages = new HashSet(); 49 | } 50 | 51 | public AgencyResultBuilder withPoints(int points) { 52 | if(this.points > 0) { 53 | throw new IllegalArgumentException("You have already set points"); 54 | } 55 | if(points <= 0 || points > 100) { 56 | throw new IllegalArgumentException("The points you set must be > 0 and <= 100 (any number between 1 and 100)"); 57 | } 58 | this.points = points; 59 | return this; 60 | } 61 | 62 | public AgencyResultBuilder withWarning(String key, String message) { 63 | this.warningMessages.add(new WarningMessage(key, message)); 64 | return this; 65 | } 66 | 67 | public AgencyResultBuilder withKoCriteria(String key, String message) { 68 | this.koCriteria.add(new KoCriteria(key, message)); 69 | return this; 70 | } 71 | 72 | public AgencyResultBuilder personId(PersonId personId) { 73 | this.personId = personId; 74 | return this; 75 | } 76 | 77 | public AgencyResultBuilder forPerson(String firstName, String lastName, String street, String postCode, String city) { 78 | if(this.personId != null) { 79 | throw new IllegalArgumentException("You have already set a person"); 80 | } 81 | this.personId = new PersonId.PersonIdBuilder(firstName, lastName) 82 | .city(city) 83 | .street(street) 84 | .postCode(postCode) 85 | .build(); 86 | return this; 87 | } 88 | 89 | public AgencyResultAggregate build() { 90 | if(this.points <= 0) { 91 | throw new IllegalStateException("Please set points > 0 with the withPoints mehtod"); 92 | } 93 | if(this.personId == null) { 94 | throw new IllegalStateException("Please set a person with the forPerson method"); 95 | } 96 | return new AgencyResultAggregate(this); 97 | } 98 | 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /scoring/adapters-input/src/main/java/com/mploed/dddwithspring/scoring/feeds/CreditAgencyPoller.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.feeds; 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper; 4 | import com.mploed.dddwithspring.scoring.appservices.ScoringApplicationService; 5 | import com.mploed.dddwithspring.scoring.incoming.creditAgency.AgencyRating; 6 | import com.rometools.rome.feed.atom.Entry; 7 | import com.rometools.rome.feed.atom.Feed; 8 | import org.apache.http.client.utils.DateUtils; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.beans.factory.annotation.Value; 13 | import org.springframework.http.*; 14 | import org.springframework.scheduling.annotation.Scheduled; 15 | import org.springframework.stereotype.Component; 16 | import org.springframework.web.client.RestTemplate; 17 | 18 | import java.io.IOException; 19 | import java.util.Date; 20 | 21 | @Component 22 | public class CreditAgencyPoller { 23 | private final Logger log = LoggerFactory.getLogger(CreditAgencyPoller.class); 24 | 25 | @Value("${creditAgencyFeed}") 26 | private String creditAgencyFeed; 27 | 28 | private Date lastModified = null; 29 | 30 | private ScoringApplicationService scoringApplicationService; 31 | 32 | // Sprint Rest Template 33 | RestTemplate restTemplate; 34 | 35 | @Autowired 36 | public CreditAgencyPoller(RestTemplate restTemplate, ScoringApplicationService scoringApplicationService) { 37 | this.lastModified = new Date(); 38 | this.restTemplate = restTemplate; 39 | this.scoringApplicationService = scoringApplicationService; 40 | 41 | } 42 | 43 | @Scheduled(fixedDelay = 30000) 44 | public void poll() { 45 | 46 | HttpHeaders requestHeaders = new HttpHeaders(); 47 | if (lastModified != null) { 48 | requestHeaders.set("If-Modified-Since", DateUtils.formatDate(lastModified)); 49 | } 50 | HttpEntity requestEntity = new HttpEntity(requestHeaders); 51 | log.info("Polling Credit Agency for new ratings"); 52 | 53 | ResponseEntity response = restTemplate.exchange(creditAgencyFeed, HttpMethod.GET, requestEntity, Feed.class); 54 | 55 | if (response.getStatusCode() != HttpStatus.NOT_MODIFIED) { 56 | Feed feed = response.getBody(); 57 | Date lastUpdateInFeed = null; 58 | ObjectMapper mapper = new ObjectMapper(); 59 | for (Entry entry : feed.getEntries()) { 60 | String ratingAsJson = entry.getSummary().getValue(); 61 | if ((lastModified == null) || (entry.getUpdated().after(lastModified))) { 62 | log.info(entry.getTitle() + " is new, processing"); 63 | try { 64 | AgencyRating agencyRating = mapper.readValue(ratingAsJson, AgencyRating.class); 65 | scoringApplicationService.scoreAgencyResult(agencyRating.getFirstName(), 66 | agencyRating.getLastName(), 67 | agencyRating.getStreet(), 68 | agencyRating.getPostCode(), 69 | agencyRating.getCity(), 70 | agencyRating.getPoints()); 71 | lastUpdateInFeed = entry.getUpdated(); 72 | } catch (IOException e) { 73 | //we should handle this exception more properly 74 | e.printStackTrace(); 75 | } 76 | 77 | } 78 | } 79 | if (response.getHeaders().getFirst("Last-Modified") != null) { 80 | lastModified = DateUtils.parseDate(response.getHeaders().getFirst("Last-Modified")); 81 | log.info("LastModified header {}", lastModified); 82 | } else { 83 | if (lastUpdateInFeed != null) { 84 | lastModified = lastUpdateInFeed; 85 | log.info("Last in feed {}", lastModified); 86 | } 87 | 88 | } 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /credit-sales-funnel/src/main/java/com/mploed/dddwithspring/creditsalesfunnel/model/household/Household.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.creditsalesfunnel.model.household; 2 | 3 | import com.mploed.dddwithspring.creditsalesfunnel.model.validation.ApplicationSubmissionGroup; 4 | 5 | import javax.persistence.*; 6 | import javax.validation.Valid; 7 | import javax.validation.constraints.Min; 8 | import javax.validation.constraints.NotEmpty; 9 | import javax.validation.constraints.NotNull; 10 | import java.io.Serializable; 11 | import java.util.Objects; 12 | 13 | @Entity 14 | public class Household implements Serializable { 15 | @Id 16 | @GeneratedValue(strategy = GenerationType.TABLE) 17 | private Long databaseId; 18 | 19 | @NotNull(groups = ApplicationSubmissionGroup.class) 20 | @NotEmpty(groups = ApplicationSubmissionGroup.class) 21 | private String applicationNumber; 22 | 23 | @Min(value = 1, groups = ApplicationSubmissionGroup.class) 24 | private int adultsInHousehold; 25 | private int childrenInHousehold; 26 | 27 | @NotNull(groups = ApplicationSubmissionGroup.class) 28 | @NotEmpty(groups = ApplicationSubmissionGroup.class) 29 | private String iban; 30 | 31 | private String bic; 32 | 33 | @Embedded 34 | @Valid 35 | @NotNull(groups = ApplicationSubmissionGroup.class) 36 | private EarningCapacity earningCapacity; 37 | 38 | @Embedded 39 | @Valid 40 | @NotNull(groups = ApplicationSubmissionGroup.class) 41 | private MonthlyExpenses monthlyExpenses; 42 | 43 | 44 | private Household() { 45 | } 46 | 47 | public Household(String applicationNumber) { 48 | this.earningCapacity = new EarningCapacity(); 49 | this.monthlyExpenses = new MonthlyExpenses(); 50 | this.applicationNumber = applicationNumber; 51 | } 52 | 53 | 54 | @Override 55 | public boolean equals(Object o) { 56 | if (this == o) return true; 57 | if (o == null || getClass() != o.getClass()) return false; 58 | Household household = (Household) o; 59 | return Objects.equals(applicationNumber, household.applicationNumber); 60 | } 61 | 62 | @Override 63 | public int hashCode() { 64 | 65 | return Objects.hash(applicationNumber); 66 | } 67 | 68 | public Long getDatabaseId() { 69 | return databaseId; 70 | } 71 | 72 | public void setDatabaseId(Long databaseId) { 73 | this.databaseId = databaseId; 74 | } 75 | 76 | public EarningCapacity getEarningCapacity() { 77 | return earningCapacity; 78 | } 79 | 80 | public void setEarningCapacity(EarningCapacity earningCapacity) { 81 | this.earningCapacity = earningCapacity; 82 | } 83 | 84 | public MonthlyExpenses getMonthlyExpenses() { 85 | return monthlyExpenses; 86 | } 87 | 88 | public void setMonthlyExpenses(MonthlyExpenses monthlyExpenses) { 89 | this.monthlyExpenses = monthlyExpenses; 90 | } 91 | 92 | public String getApplicationNumber() { 93 | return applicationNumber; 94 | } 95 | 96 | public int getAdultsInHousehold() { 97 | return adultsInHousehold; 98 | } 99 | 100 | public void setAdultsInHousehold(int adultsInHousehold) { 101 | this.adultsInHousehold = adultsInHousehold; 102 | } 103 | 104 | public int getChildrenInHousehold() { 105 | return childrenInHousehold; 106 | } 107 | 108 | public void setChildrenInHousehold(int childrenInHousehold) { 109 | this.childrenInHousehold = childrenInHousehold; 110 | } 111 | 112 | public String getIban() { 113 | return iban; 114 | } 115 | 116 | public void setIban(String iban) { 117 | this.iban = iban; 118 | } 119 | 120 | public String getBic() { 121 | return bic; 122 | } 123 | 124 | public void setBic(String bic) { 125 | this.bic = bic; 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /scoring/aggregates/src/test/java/com/mploed/dddwithspring/scoring/archunit/AggregateArchitectureTest.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.archunit; 2 | 3 | import java.net.URL; 4 | 5 | import com.mploed.dddwithspring.scoring.agencyResult.AgencyResultAggregate; 6 | import com.mploed.dddwithspring.scoring.applicant.ApplicantAggregate; 7 | import com.mploed.dddwithspring.scoring.financialSituation.FinancialSituationAggregate; 8 | import com.mploed.dddwithspring.scoring.microarchitecture.Aggregate; 9 | import com.mploed.dddwithspring.scoring.microarchitecture.AggregateBuilder; 10 | import com.mploed.dddwithspring.scoring.scoringResult.ScoringResultAggregate; 11 | import com.tngtech.archunit.core.domain.JavaClasses; 12 | import com.tngtech.archunit.core.importer.ImportOption; 13 | import com.tngtech.archunit.junit.AnalyzeClasses; 14 | import com.tngtech.archunit.junit.ArchTest; 15 | import com.tngtech.archunit.junit.ArchUnitRunner; 16 | import com.tngtech.archunit.lang.ArchRule; 17 | import org.junit.runner.RunWith; 18 | import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes; 19 | import static com.tngtech.archunit.library.plantuml.PlantUmlArchCondition.Configurations.consideringOnlyDependenciesInAnyPackage; 20 | import static com.tngtech.archunit.library.plantuml.PlantUmlArchCondition.adhereToPlantUmlDiagram; 21 | 22 | @RunWith(ArchUnitRunner.class) 23 | @AnalyzeClasses( 24 | packagesOf = {ScoringResultAggregate.class, ApplicantAggregate.class, FinancialSituationAggregate.class, AgencyResultAggregate.class}, 25 | importOptions = ImportOption.DoNotIncludeTests.class) 26 | public class AggregateArchitectureTest { 27 | private static final URL scoringDiagram = AggregateArchitectureTest.class.getResource("scoring.puml"); 28 | 29 | @ArchTest 30 | public static ArchRule entityAndValueObjectVisibilityRule = 31 | classes() 32 | .that().areNotAnnotatedWith(Aggregate.class) 33 | .and().areNotAnnotatedWith(AggregateBuilder.class) 34 | .should().bePackagePrivate(); 35 | 36 | @ArchTest 37 | public static void aggregateAnnotationRules(JavaClasses importedClasses) { 38 | ArchRule namingToAnnotation = classes().that().haveSimpleNameEndingWith("Aggregate").should().beAnnotatedWith(Aggregate.class); 39 | namingToAnnotation.check(importedClasses); 40 | 41 | ArchRule annotationToNaming = classes().that().areAnnotatedWith(Aggregate.class).should().haveSimpleNameEndingWith("Aggregate"); 42 | annotationToNaming.check(importedClasses); 43 | } 44 | 45 | @ArchTest 46 | public static ArchRule aggregateVisibilityRule = 47 | classes().that().areAnnotatedWith(Aggregate.class).should().bePublic(); 48 | 49 | //this test has and exception for the application aggregate because here I merged the aggregate and the root entity 50 | //in order showcase a different style for the implementation of aggregates 51 | @ArchTest 52 | public static ArchRule aggregateToRootEntityReference = 53 | classes() 54 | .that().areAnnotatedWith(Aggregate.class) 55 | .and().haveSimpleNameNotEndingWith("ApplicantAggregate") 56 | .should().accessClassesThat().haveSimpleNameEndingWith("RootEntity"); 57 | 58 | @ArchTest 59 | public static final ArchRule aggregateFrameworkRule = 60 | classes() 61 | .should().onlyDependOnClassesThat().resideInAnyPackage("com.mploed.dddwithspring..", "java..", ""); 62 | 63 | @ArchTest 64 | public static final ArchRule subdomainDependenciesRule = 65 | classes() 66 | .should(adhereToPlantUmlDiagram(scoringDiagram, 67 | consideringOnlyDependenciesInAnyPackage("com.mploed.dddwithspring.."))); 68 | } 69 | -------------------------------------------------------------------------------- /credit-sales-funnel/src/main/resources/templates/layout/baseLayout.html: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 13 | 14 | 15 | 16 | 17 | Big Pug Loans 18 | 19 | 20 | 21 | 22 |
23 | 58 | 59 |
60 |
Application Number:
61 | 62 |
63 |
64 | Whatever content there is 65 |
66 |
67 | 68 | 69 | 70 | 73 | 76 | 79 | 80 | -------------------------------------------------------------------------------- /scoring/aggregates/src/main/java/com/mploed/dddwithspring/scoring/applicant/ApplicantAggregate.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.applicant; 2 | 3 | 4 | import com.mploed.dddwithspring.scoring.ApplicationNumber; 5 | import com.mploed.dddwithspring.scoring.Money; 6 | import com.mploed.dddwithspring.scoring.PersonId; 7 | import com.mploed.dddwithspring.scoring.microarchitecture.Aggregate; 8 | import com.mploed.dddwithspring.scoring.microarchitecture.AggregateBuilder; 9 | 10 | import java.math.BigDecimal; 11 | 12 | @Aggregate 13 | public class ApplicantAggregate { 14 | private final PersonId personId; 15 | private final ApplicationNumber applicationNumber; 16 | private final String name; 17 | private final String lastName; 18 | private final Address address; 19 | private final AccountBalance balance; 20 | 21 | 22 | private ApplicantAggregate(ApplicantAggregateBuilder builder) { 23 | PersonId personId = new PersonId.PersonIdBuilder(builder.firstName, builder.lastName) 24 | .postCode(builder.postCode) 25 | .city(builder.city) 26 | .street(builder.street) 27 | .build(); 28 | 29 | Address address = new Address(builder.street, builder.postCode, builder.city); 30 | this.address = address; 31 | this.applicationNumber = builder.applicationNumber; 32 | this.balance = builder.accountBalance; 33 | this.lastName = builder.lastName; 34 | this.personId = personId; 35 | this.name = builder.firstName; 36 | 37 | 38 | } 39 | 40 | public int calculateScoringPoints() { 41 | int result = 0; 42 | result += balance.calculateScoringPoints(); 43 | result += address.calculateScoringPoints(); 44 | return result; 45 | } 46 | 47 | public ApplicationNumber getApplicationNumber() { 48 | return this.applicationNumber; 49 | } 50 | 51 | public PersonId getPersonId() { 52 | return this.personId; 53 | } 54 | 55 | String getName() { 56 | return name; 57 | } 58 | 59 | String getLastName() { 60 | return lastName; 61 | } 62 | 63 | Address getAddress() { 64 | return address; 65 | } 66 | 67 | AccountBalance getBalance() { 68 | return balance; 69 | } 70 | 71 | @AggregateBuilder 72 | public static class ApplicantAggregateBuilder { 73 | private String firstName; 74 | private String lastName; 75 | private final ApplicationNumber applicationNumber; 76 | private String street; 77 | private String postCode; 78 | private String city; 79 | private AccountBalance accountBalance; 80 | 81 | 82 | public ApplicantAggregateBuilder(ApplicationNumber applicationNumber) { 83 | this.applicationNumber = applicationNumber; 84 | } 85 | 86 | public ApplicantAggregateBuilder firstName(String firstName) { 87 | this.firstName = firstName; 88 | return this; 89 | } 90 | 91 | public ApplicantAggregateBuilder lastName(String lastName) { 92 | this.lastName = lastName; 93 | return this; 94 | } 95 | 96 | public ApplicantAggregateBuilder street(String street) { 97 | this.street = street; 98 | return this; 99 | } 100 | 101 | public ApplicantAggregateBuilder postCode(String postCode) { 102 | this.postCode = postCode; 103 | return this; 104 | } 105 | 106 | public ApplicantAggregateBuilder city(String city) { 107 | this.city = city; 108 | return this; 109 | } 110 | 111 | public ApplicantAggregateBuilder accountBalance(int balance) { 112 | this.accountBalance = new AccountBalance(new Money(balance)); 113 | return this; 114 | } 115 | 116 | public ApplicantAggregateBuilder accountBalance(BigDecimal balance) { 117 | this.accountBalance = new AccountBalance(new Money(balance)); 118 | return this; 119 | } 120 | 121 | public ApplicantAggregate build() { 122 | if(this.accountBalance == null) { 123 | this.accountBalance = new AccountBalance(new Money()); 124 | } 125 | return new ApplicantAggregate(this); 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /scoring/adapters-input/src/main/java/com/mploed/dddwithspring/scoring/incoming/applicant/Applicant.java: -------------------------------------------------------------------------------- 1 | package com.mploed.dddwithspring.scoring.incoming.applicant; 2 | 3 | import java.io.Serializable; 4 | import java.util.Date; 5 | import java.util.Objects; 6 | 7 | public class Applicant implements Serializable { 8 | private Long databaseId; 9 | 10 | private String applicationNumber; 11 | 12 | private String applicantNumber; 13 | 14 | private String customerNumber; 15 | 16 | private String firstName; 17 | 18 | private String lastName; 19 | 20 | private Address address; 21 | 22 | private MaritalStatus maritalStatus; 23 | 24 | private Business business; 25 | 26 | private Employment employment; 27 | 28 | private String employer; 29 | 30 | private Date employedSince; 31 | 32 | private Date birthday; 33 | 34 | public Applicant(String applicationNumber, String applicantNumber) { 35 | this.address = new Address(); 36 | this.applicationNumber = applicationNumber; 37 | this.applicantNumber = applicantNumber; 38 | } 39 | 40 | public Applicant() { 41 | this.address = new Address(); 42 | } 43 | 44 | @Override 45 | public boolean equals(Object o) { 46 | if (this == o) return true; 47 | if (o == null || getClass() != o.getClass()) return false; 48 | Applicant applicant = (Applicant) o; 49 | return Objects.equals(applicationNumber, applicant.applicationNumber) && 50 | Objects.equals(applicantNumber, applicant.applicantNumber); 51 | } 52 | 53 | @Override 54 | public int hashCode() { 55 | 56 | return Objects.hash(applicationNumber, applicantNumber); 57 | } 58 | 59 | public Long getDatabaseId() { 60 | return databaseId; 61 | } 62 | 63 | public void setDatabaseId(Long databaseId) { 64 | this.databaseId = databaseId; 65 | } 66 | 67 | public String getApplicantNumber() { 68 | return applicantNumber; 69 | } 70 | 71 | public void setApplicantNumber(String applicantNumber) { 72 | this.applicantNumber = applicantNumber; 73 | } 74 | 75 | public String getApplicationNumber() { 76 | return applicationNumber; 77 | } 78 | 79 | public void setApplicationNumber(String applicationNumber) { 80 | this.applicationNumber = applicationNumber; 81 | } 82 | 83 | public String getCustomerNumber() { 84 | return customerNumber; 85 | } 86 | 87 | public void setCustomerNumber(String customerNumber) { 88 | this.customerNumber = customerNumber; 89 | } 90 | 91 | public String getFirstName() { 92 | return firstName; 93 | } 94 | 95 | public void setFirstName(String firstName) { 96 | this.firstName = firstName; 97 | } 98 | 99 | public String getLastName() { 100 | return lastName; 101 | } 102 | 103 | public void setLastName(String lastName) { 104 | this.lastName = lastName; 105 | } 106 | 107 | public Address getAddress() { 108 | return address; 109 | } 110 | 111 | public void setAddress(Address address) { 112 | this.address = address; 113 | } 114 | 115 | public MaritalStatus getMaritalStatus() { 116 | return maritalStatus; 117 | } 118 | 119 | public void setMaritalStatus(MaritalStatus maritalStatus) { 120 | this.maritalStatus = maritalStatus; 121 | } 122 | 123 | public Business getBusiness() { 124 | return business; 125 | } 126 | 127 | public void setBusiness(Business business) { 128 | this.business = business; 129 | } 130 | 131 | public Employment getEmployment() { 132 | return employment; 133 | } 134 | 135 | public void setEmployment(Employment employment) { 136 | this.employment = employment; 137 | } 138 | 139 | public String getEmployer() { 140 | return employer; 141 | } 142 | 143 | public void setEmployer(String employer) { 144 | this.employer = employer; 145 | } 146 | 147 | public Date getEmployedSince() { 148 | return employedSince; 149 | } 150 | 151 | public void setEmployedSince(Date employedSince) { 152 | this.employedSince = employedSince; 153 | } 154 | 155 | public Date getBirthday() { 156 | return birthday; 157 | } 158 | 159 | public void setBirthday(Date birthday) { 160 | this.birthday = birthday; 161 | } 162 | 163 | 164 | } 165 | --------------------------------------------------------------------------------