This repository has been archived by the owner on Jan 10, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathkalix-es-java-loanapplication.xml
100 lines (100 loc) · 19.3 KB
/
kalix-es-java-loanapplication.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
<templateSet group="kalix-es-java-loanapplication">
<template name="aheader" value="// This is the public API offered by your entity. syntax = "proto3"; import "google/protobuf/empty.proto"; import "google/protobuf/timestamp.proto"; import "kalix/annotations.proto"; import "google/api/annotations.proto"; package com.example.loanapp; option java_outer_classname = "LoanAppApi";" description="" toReformat="false" toShortenFQNames="true">
<context>
<option name="PROTO" value="true" />
<option name="PROTOTEXT" value="true" />
</context>
</template>
<template name="astate" value="message LoanAppState { string client_id = 1; int64 client_monthly_income_cents = 2; int64 loan_amount_cents = 3; int32 loan_duration_months = 4; LoanAppStatus status = 5; string decline_reason = 6; google.protobuf.Timestamp last_update_timestamp = 7; } enum LoanAppStatus { STATUS_UNKNOWN = 0; STATUS_IN_REVIEW = 1; STATUS_APPROVED = 2; STATUS_DECLINED = 3; }" description="" toReformat="false" toShortenFQNames="true">
<context>
<option name="PROTO" value="true" />
<option name="PROTOTEXT" value="true" />
</context>
</template>
<template name="acmd" value="message SubmitCommand { string loan_app_id = 1 [(kalix.field).entity_key = true]; string client_id = 2; int64 client_monthly_income_cents = 6; int64 loan_amount_cents = 7; int32 loan_duration_months = 8; } message GetCommand { string loan_app_id = 1 [(kalix.field).entity_key = true]; } message ApproveCommand { string loan_app_id = 1 [(kalix.field).entity_key = true]; } message DeclineCommand { string loan_app_id = 1 [(kalix.field).entity_key = true]; string reason = 2; }" description="" toReformat="false" toShortenFQNames="true">
<context>
<option name="PROTO" value="true" />
<option name="PROTOTEXT" value="true" />
</context>
</template>
<template name="asrv" value="service LoanAppService { }" description="" toReformat="false" toShortenFQNames="true">
<context>
<option name="PROTO" value="true" />
<option name="PROTOTEXT" value="true" />
</context>
</template>
<template name="afunc" value="rpc Submit(SubmitCommand) returns (google.protobuf.Empty) { option (google.api.http) = { post: "/loanapp/{loan_app_id}" body: "*" }; } rpc Get(GetCommand) returns (LoanAppState) { option (google.api.http) = { get: "/loanapp/{loan_app_id}" }; } rpc Approve(ApproveCommand) returns (google.protobuf.Empty) { option (google.api.http) = { put: "/loanapp/{loan_app_id}/approve" }; } rpc Decline(DeclineCommand) returns (google.protobuf.Empty) { option (google.api.http) = { put: "/loanapp/{loan_app_id}/decline" body: "*" }; }" description="" toReformat="false" toShortenFQNames="true">
<context>
<option name="PROTO" value="true" />
<option name="PROTOTEXT" value="true" />
</context>
</template>
<template name="acodegen" value=" option (kalix.codegen) = { event_sourced_entity: { name: "com.example.loanapp.domain.LoanAppEntity" entity_type: "loanapp" state: "com.example.loanapp.domain.LoanAppDomainState" events: [ "com.example.loanapp.domain.Submitted", "com.example.loanapp.domain.Approved", "com.example.loanapp.domain.Declined" ] } };" description="" toReformat="false" toShortenFQNames="true">
<context>
<option name="PROTO" value="true" />
<option name="PROTOTEXT" value="true" />
</context>
</template>
<template name="dheader" value="syntax = "proto3"; import "google/protobuf/timestamp.proto"; package com.example.loanapp.domain; option java_outer_classname = "LoanAppDomain";" description="" toReformat="false" toShortenFQNames="true">
<context>
<option name="PROTO" value="true" />
<option name="PROTOTEXT" value="true" />
</context>
</template>
<template name="dstate" value="message LoanAppDomainState { string client_id = 1; int64 client_monthly_income_cents = 2; int64 loan_amount_cents = 3; int32 loan_duration_months = 4; LoanAppDomainStatus status = 5; string decline_reason = 6; google.protobuf.Timestamp last_update_timestamp = 7; } enum LoanAppDomainStatus { STATUS_UNKNOWN = 0; STATUS_IN_REVIEW = 1; STATUS_APPROVED = 2; STATUS_DECLINED = 3; }" description="" toReformat="false" toShortenFQNames="true">
<context>
<option name="PROTO" value="true" />
<option name="PROTOTEXT" value="true" />
</context>
</template>
<template name="devts" value="message Submitted { string loan_app_id = 1; string client_id = 2; int64 client_monthly_income_cents = 3; int64 loan_amount_cents = 4; int32 loan_duration_months = 5; google.protobuf.Timestamp event_timestamp = 6; } message Approved { string loan_app_id = 1; google.protobuf.Timestamp event_timestamp = 2; } message Declined { string loan_app_id = 1; string reason = 2; google.protobuf.Timestamp event_timestamp = 3; }" description="" toReformat="false" toShortenFQNames="true">
<context>
<option name="PROTO" value="true" />
<option name="PROTOTEXT" value="true" />
</context>
</template>
<template name="eall" value="public static final String ERROR_NOT_FOUND = "Not found"; public static final String ERROR_WRONG_STATUS = "Wrong status"; @Override public LoanAppDomain.LoanAppDomainState emptyState() { return LoanAppDomain.LoanAppDomainState.getDefaultInstance(); } @Override public Effect<Empty> submit(LoanAppDomain.LoanAppDomainState currentState, LoanAppApi.SubmitCommand submitCommand) { if (currentState.equals(LoanAppDomain.LoanAppDomainState.getDefaultInstance())) { LoanAppDomain.Submitted event = LoanAppDomain.Submitted.newBuilder() .setLoanAppId(submitCommand.getLoanAppId()) .setClientId(submitCommand.getClientId()) .setClientMonthlyIncomeCents(submitCommand.getClientMonthlyIncomeCents()) .setLoanAmountCents(submitCommand.getLoanAmountCents()) .setLoanDurationMonths(submitCommand.getLoanDurationMonths()) .setEventTimestamp(com.google.protobuf.util.Timestamps.fromMillis(System.currentTimeMillis())) .build(); return effects().emitEvent(event).thenReply(__ -> Empty.getDefaultInstance()); } else if (currentState.getStatus() == LoanAppDomain.LoanAppDomainStatus.STATUS_IN_REVIEW) { return effects().reply(Empty.getDefaultInstance()); } else { return effects().error(ERROR_WRONG_STATUS); } } @Override public Effect<LoanAppApi.LoanAppState> get(LoanAppDomain.LoanAppDomainState currentState, LoanAppApi.GetCommand getCommand) { if(currentState.equals(LoanAppDomain.LoanAppDomainState.getDefaultInstance())) return effects().error(ERROR_NOT_FOUND); return effects().reply(map(currentState)); } private LoanAppApi.LoanAppState map(LoanAppDomain.LoanAppDomainState state){ return LoanAppApi.LoanAppState.newBuilder() .setClientId(state.getClientId()) .setClientMonthlyIncomeCents(state.getClientMonthlyIncomeCents()) .setLoanAmountCents(state.getLoanAmountCents()) .setLoanDurationMonths(state.getLoanDurationMonths()) .setLastUpdateTimestamp(state.getLastUpdateTimestamp()) .setStatus(map(state.getStatus())) .setDeclineReason(state.getDeclineReason()) .build(); } private LoanAppApi.LoanAppStatus map(LoanAppDomain.LoanAppDomainStatus status){ return LoanAppApi.LoanAppStatus.forNumber(status.getNumber()); } @Override public Effect<Empty> approve(LoanAppDomain.LoanAppDomainState currentState, LoanAppApi.ApproveCommand approveCommand) { if(currentState.equals(LoanAppDomain.LoanAppDomainState.getDefaultInstance())) return effects().error(ERROR_NOT_FOUND); if(currentState.getStatus() == LoanAppDomain.LoanAppDomainStatus.STATUS_IN_REVIEW){ LoanAppDomain.Approved event = LoanAppDomain.Approved.newBuilder() .setLoanAppId(approveCommand.getLoanAppId()) .setEventTimestamp(com.google.protobuf.util.Timestamps.fromMillis(System.currentTimeMillis())).build(); return effects().emitEvent(event).thenReply(__ -> Empty.getDefaultInstance()); }else if(currentState.getStatus() == LoanAppDomain.LoanAppDomainStatus.STATUS_APPROVED) return effects().reply(Empty.getDefaultInstance()); else return effects().error(ERROR_WRONG_STATUS); } @Override public Effect<Empty> decline(LoanAppDomain.LoanAppDomainState currentState, LoanAppApi.DeclineCommand declineCommand) { if(currentState.equals(LoanAppDomain.LoanAppDomainState.getDefaultInstance())) return effects().error(ERROR_NOT_FOUND); if(currentState.getStatus() == LoanAppDomain.LoanAppDomainStatus.STATUS_IN_REVIEW){ LoanAppDomain.Declined event = LoanAppDomain.Declined.newBuilder() .setLoanAppId(declineCommand.getLoanAppId()) .setReason(declineCommand.getReason()) .setEventTimestamp(com.google.protobuf.util.Timestamps.fromMillis(System.currentTimeMillis())).build(); return effects().emitEvent(event).thenReply(__ -> Empty.getDefaultInstance()); }else if(currentState.getStatus() == LoanAppDomain.LoanAppDomainStatus.STATUS_DECLINED) return effects().reply(Empty.getDefaultInstance()); else return effects().error(ERROR_WRONG_STATUS); } @Override public LoanAppDomain.LoanAppDomainState submitted(LoanAppDomain.LoanAppDomainState currentState, LoanAppDomain.Submitted submitted) { return LoanAppDomain.LoanAppDomainState.newBuilder() .setClientId(submitted.getClientId()) .setClientMonthlyIncomeCents(submitted.getClientMonthlyIncomeCents()) .setLoanAmountCents(submitted.getLoanAmountCents()) .setLoanDurationMonths(submitted.getLoanDurationMonths()) .setLastUpdateTimestamp(submitted.getEventTimestamp()) .setStatus(LoanAppDomain.LoanAppDomainStatus.STATUS_IN_REVIEW) .build(); } @Override public LoanAppDomain.LoanAppDomainState approved(LoanAppDomain.LoanAppDomainState currentState, LoanAppDomain.Approved approved) { return currentState.toBuilder().setStatus(LoanAppDomain.LoanAppDomainStatus.STATUS_APPROVED).setLastUpdateTimestamp(approved.getEventTimestamp()).build(); } @Override public LoanAppDomain.LoanAppDomainState declined(LoanAppDomain.LoanAppDomainState currentState, LoanAppDomain.Declined declined) { return currentState.toBuilder().setStatus(LoanAppDomain.LoanAppDomainStatus.STATUS_DECLINED).setDeclineReason(declined.getReason()).setLastUpdateTimestamp(declined.getEventTimestamp()).build(); }" description="" toReformat="false" toShortenFQNames="true">
<context>
<option name="JAVA_CODE" value="true" />
</context>
</template>
<template name="ut" value="@Test public void happyPath() { String loanAppId = java.util.UUID.randomUUID().toString(); LoanAppEntityTestKit testKit = LoanAppEntityTestKit.of(loanAppId,LoanAppEntity::new); submitLoan(testKit,loanAppId); EventSourcedResult<Empty> result = testKit.approve(LoanAppApi.ApproveCommand.newBuilder().setLoanAppId(loanAppId).build()); LoanAppDomain.Approved event = result.getNextEventOfType(LoanAppDomain.Approved.class); assertEquals(event.getLoanAppId(),loanAppId); assertGet(testKit,loanAppId, LoanAppApi.LoanAppStatus.STATUS_APPROVED); } private void submitLoan(LoanAppEntityTestKit testKit,String loanAppId){ EventSourcedResult<Empty> result = testKit.submit(create(loanAppId)); LoanAppDomain.Submitted event = result.getNextEventOfType(LoanAppDomain.Submitted.class); assertEquals(event.getLoanAppId(),loanAppId); assertGet(testKit,loanAppId, LoanAppApi.LoanAppStatus.STATUS_IN_REVIEW); } private LoanAppApi.SubmitCommand create(String loanAppId){ return create(loanAppId,1000,500,24); } private LoanAppApi.SubmitCommand create(String loanAppId, long monthlyIncomeCents, long loanAmountCents, int loanDurationMonths){ return LoanAppApi.SubmitCommand.newBuilder() .setLoanAppId(loanAppId) .setClientId(java.util.UUID.randomUUID().toString()) .setClientMonthlyIncomeCents(monthlyIncomeCents) .setLoanAmountCents(loanAmountCents) .setLoanDurationMonths(loanDurationMonths) .build(); } private void assertGet(LoanAppEntityTestKit testKit,String loanAppId, LoanAppApi.LoanAppStatus status){ EventSourcedResult<LoanAppApi.LoanAppState> getResult = testKit.get(LoanAppApi.GetCommand.newBuilder().setLoanAppId(loanAppId).build()); assertFalse(getResult.didEmitEvents()); assertEquals(status,getResult.getReply().getStatus()); }" description="" toReformat="false" toShortenFQNames="true">
<context>
<option name="JAVA_CODE" value="true" />
</context>
</template>
<template name="it" value="@Test public void happyPath() throws Exception { String loanAppId = java.util.UUID.randomUUID().toString(); client.submit(create(loanAppId)).toCompletableFuture().get(5, SECONDS); assertGet(loanAppId, LoanAppApi.LoanAppStatus.STATUS_IN_REVIEW); client.approve(LoanAppApi.ApproveCommand.newBuilder().setLoanAppId(loanAppId).build()).toCompletableFuture().get(5, SECONDS); assertGet(loanAppId, LoanAppApi.LoanAppStatus.STATUS_APPROVED); } private LoanAppApi.SubmitCommand create(String loanAppId, long monthlyIncomeCents, long loanAmountCents, int loanDurationMonths){ return LoanAppApi.SubmitCommand.newBuilder() .setLoanAppId(loanAppId) .setClientId(java.util.UUID.randomUUID().toString()) .setClientMonthlyIncomeCents(monthlyIncomeCents) .setLoanAmountCents(loanAmountCents) .setLoanDurationMonths(loanDurationMonths) .build(); } private LoanAppApi.SubmitCommand create(String loanAppId){ return create(loanAppId,1000,500,24); } private void assertGet(String loanAppId, LoanAppApi.LoanAppStatus status) throws Exception{ LoanAppApi.LoanAppState loanApp = client.get(LoanAppApi.GetCommand.newBuilder().setLoanAppId(loanAppId).build()).toCompletableFuture().get(5,SECONDS); org.junit.Assert.assertNotNull(loanApp); org.junit.Assert.assertEquals(status,loanApp.getStatus()); }" description="" toReformat="false" toShortenFQNames="true">
<context>
<option name="JAVA_CODE" value="true" />
</context>
</template>
<template name="theader" value="syntax = "proto3"; package com.example.loanapp; import "google/api/annotations.proto"; import "google/protobuf/any.proto"; import "google/protobuf/empty.proto"; import "google/protobuf/timestamp.proto"; import "kalix/annotations.proto"; import "com/example/loanapp/domain/loan_app_domain.proto"; option java_outer_classname = "LoanAppToTopicApi";" description="" toReformat="false" toShortenFQNames="true">
<context>
<option name="PROTO" value="true" />
<option name="PROTOTEXT" value="true" />
</context>
</template>
<template name="tevts" value="message ApprovedTopic { string loan_app_id = 1; google.protobuf.Timestamp event_timestamp = 2; } message DeclinedTopic { string loan_app_id = 1; string reason = 2; google.protobuf.Timestamp event_timestamp = 3; }" description="" toReformat="false" toShortenFQNames="true">
<context>
<option name="PROTO" value="true" />
<option name="PROTOTEXT" value="true" />
</context>
</template>
<template name="tsrv" value="service LoanAppToTopic { }" description="" toReformat="false" toShortenFQNames="true">
<context>
<option name="PROTO" value="true" />
<option name="PROTOTEXT" value="true" />
</context>
</template>
<template name="tfunc" value="option (kalix.codegen) = { action: {} }; rpc OnApproved(domain.Approved) returns (ApprovedTopic) { option (kalix.method).eventing.in = { event_sourced_entity: "loanapp" }; option (kalix.method).eventing.out = { topic: "loanapp-topic" }; } rpc OnDeclined(domain.Declined) returns (DeclinedTopic) { option (kalix.method).eventing.in = { event_sourced_entity: "loanapp" }; option (kalix.method).eventing.out = { topic: "loanapp-topic" }; } rpc IgnoreOtherEvents(google.protobuf.Any) returns (google.protobuf.Empty) { option (kalix.method).eventing.in = { event_sourced_entity: "loanapp" }; }" description="" toReformat="false" toShortenFQNames="true">
<context>
<option name="PROTO" value="true" />
<option name="PROTOTEXT" value="true" />
</context>
</template>
<template name="tall" value="@Override public Effect<LoanAppToTopicApi.ApprovedTopic> onApproved(LoanAppDomain.Approved approved) { LoanAppToTopicApi.ApprovedTopic topicEvent = LoanAppToTopicApi.ApprovedTopic.newBuilder() .setLoanAppId(approved.getLoanAppId()) .setEventTimestamp(approved.getEventTimestamp()) .build(); return effects().reply(topicEvent); } @Override public Effect<LoanAppToTopicApi.DeclinedTopic> onDeclined(LoanAppDomain.Declined declined) { LoanAppToTopicApi.DeclinedTopic topicEvent = LoanAppToTopicApi.DeclinedTopic.newBuilder() .setLoanAppId(declined.getLoanAppId()) .setReason(declined.getReason()) .setEventTimestamp(declined.getEventTimestamp()) .build(); return effects().reply(topicEvent); } @Override public Effect<Empty> ignoreOtherEvents(Any any) { return effects().reply(Empty.getDefaultInstance()); }" description="" toReformat="false" toShortenFQNames="true">
<context>
<option name="JAVA_CODE" value="true" />
</context>
</template>
</templateSet>