eva4j 1.0.16 → 1.0.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +220 -5
- package/DOMAIN_YAML_GUIDE.md +188 -3
- package/FUTURE_FEATURES.md +33 -52
- package/QUICK_REFERENCE.md +8 -4
- package/bin/eva4j.js +70 -2
- package/config/defaults.json +1 -0
- package/docs/CAMUNDA_DMN_GUIDE.md +1380 -0
- package/docs/KAFKA_PRODUCTION_CONFIG.md +441 -0
- package/docs/RABBITMQ_PRODUCTION_CONFIG.md +227 -0
- package/docs/commands/ADD_RABBITMQ_CLIENT.md +192 -0
- package/docs/commands/EVALUATE_SYSTEM.md +290 -10
- package/docs/commands/GENERATE_RABBITMQ_EVENT.md +341 -0
- package/docs/commands/GENERATE_RABBITMQ_LISTENER.md +595 -0
- package/docs/commands/GENERATE_TEMPORAL_FLOW.md +52 -12
- package/docs/commands/INDEX.md +27 -3
- package/docs/prototype/TEMPORAL_COMMUNICATION_PATTERNS.md +731 -0
- package/docs/prototype/TEMPORAL_DESIGN_METHODOLOGY.md +740 -0
- package/docs/prototype/system/RISKS.md +277 -0
- package/docs/prototype/system/customers.yaml +133 -0
- package/docs/prototype/system/inventory.yaml +109 -0
- package/docs/prototype/system/notifications.yaml +131 -0
- package/docs/prototype/system/orders.yaml +241 -0
- package/docs/prototype/system/payments.yaml +256 -0
- package/docs/prototype/system/products.yaml +168 -0
- package/docs/prototype/system/system.yaml +269 -0
- package/examples/domain-endpoints-multi-aggregate.yaml +140 -0
- package/examples/domain-events.yaml +26 -0
- package/examples/domain-read-models.yaml +113 -0
- package/examples/system/customer.yaml +89 -0
- package/examples/system/orders.yaml +119 -0
- package/examples/system/product.yaml +27 -0
- package/examples/system/system.yaml +80 -0
- package/package.json +1 -1
- package/read-model-spec.md +664 -0
- package/src/agents/design-gap-analyst-temporal.agent.md +452 -0
- package/src/agents/design-gap-analyst.agent.md +383 -0
- package/src/agents/design-reviewer-temporal.agent.md +412 -0
- package/src/agents/design-reviewer.agent.md +34 -5
- package/src/agents/implement-use-cases.prompt.md +179 -0
- package/src/agents/ux-gap-analyst.agent.md +412 -0
- package/src/commands/add-rabbitmq-client.js +261 -0
- package/src/commands/add-temporal-client.js +22 -2
- package/src/commands/build.js +267 -11
- package/src/commands/evaluate-system.js +700 -13
- package/src/commands/generate-entities.js +560 -24
- package/src/commands/generate-http-exchange.js +3 -0
- package/src/commands/generate-kafka-event.js +3 -0
- package/src/commands/generate-kafka-listener.js +3 -0
- package/src/commands/generate-rabbitmq-event.js +665 -0
- package/src/commands/generate-rabbitmq-listener.js +205 -0
- package/src/commands/generate-record.js +2 -2
- package/src/commands/generate-resource.js +4 -1
- package/src/commands/generate-temporal-activity.js +970 -33
- package/src/commands/generate-temporal-flow.js +98 -38
- package/src/commands/generate-temporal-system.js +708 -0
- package/src/commands/generate-usecase.js +4 -1
- package/src/skills/build-system-yaml/SKILL.md +343 -2
- package/src/skills/build-system-yaml/references/domain-yaml-spec.md +253 -26
- package/src/skills/build-system-yaml/references/module-spec.md +90 -9
- package/src/skills/build-system-yaml/references/system-yaml-spec.md +36 -0
- package/src/skills/build-temporal-system/SKILL.md +752 -0
- package/src/skills/build-temporal-system/references/temporal-communication-patterns.md +167 -0
- package/src/skills/build-temporal-system/references/temporal-domain-yaml-spec.md +449 -0
- package/src/skills/build-temporal-system/references/temporal-module-spec.md +353 -0
- package/src/skills/build-temporal-system/references/temporal-system-yaml-spec.md +326 -0
- package/src/skills/implement-use-case/SKILL.md +350 -0
- package/src/skills/implement-use-case/references/use-case-patterns.md +980 -0
- package/src/skills/requirements-elicitation/SKILL.md +228 -0
- package/src/skills/requirements-elicitation/references/interview-framework.md +260 -0
- package/src/skills/requirements-elicitation/references/output-templates.md +368 -0
- package/src/utils/bounded-context-diagram.js +844 -0
- package/src/utils/config-manager.js +4 -2
- package/src/utils/domain-validator.js +495 -17
- package/src/utils/naming.js +20 -0
- package/src/utils/system-validator.js +169 -11
- package/src/utils/system-yaml-parser.js +318 -0
- package/src/utils/temporal-validator.js +497 -0
- package/src/utils/validator.js +3 -1
- package/src/utils/yaml-to-entity.js +281 -9
- package/templates/aggregate/AggregateRepository.java.ejs +4 -0
- package/templates/aggregate/AggregateRepositoryImpl.java.ejs +8 -0
- package/templates/aggregate/AggregateRoot.java.ejs +38 -4
- package/templates/aggregate/DomainEventHandler.java.ejs +116 -22
- package/templates/aggregate/JpaAggregateRoot.java.ejs +4 -4
- package/templates/aggregate/JpaEntity.java.ejs +2 -2
- package/templates/base/docker/rabbitmq-services.yaml.ejs +12 -0
- package/templates/base/resources/parameters/develop/kafka.yaml.ejs +5 -0
- package/templates/base/resources/parameters/develop/rabbitmq.yaml.ejs +15 -0
- package/templates/base/resources/parameters/develop/temporal.yaml.ejs +0 -3
- package/templates/base/resources/parameters/local/kafka.yaml.ejs +5 -0
- package/templates/base/resources/parameters/local/rabbitmq.yaml.ejs +15 -0
- package/templates/base/resources/parameters/local/temporal.yaml.ejs +0 -3
- package/templates/base/resources/parameters/production/kafka.yaml.ejs +39 -8
- package/templates/base/resources/parameters/production/rabbitmq.yaml.ejs +32 -0
- package/templates/base/resources/parameters/production/temporal.yaml.ejs +0 -3
- package/templates/base/resources/parameters/test/kafka.yaml.ejs +12 -6
- package/templates/base/resources/parameters/test/rabbitmq.yaml.ejs +15 -0
- package/templates/base/resources/parameters/test/temporal.yaml.ejs +0 -3
- package/templates/base/root/AGENTS.md.ejs +1 -1
- package/templates/crud/DeleteCommandHandler.java.ejs +19 -1
- package/templates/crud/EndpointsController.java.ejs +1 -1
- package/templates/crud/ScaffoldCommand.java.ejs +5 -2
- package/templates/crud/ScaffoldCommandHandler.java.ejs +3 -1
- package/templates/crud/ScaffoldQuery.java.ejs +5 -2
- package/templates/crud/ScaffoldQueryHandler.java.ejs +3 -1
- package/templates/crud/SubEntityRemoveCommand.java.ejs +1 -1
- package/templates/crud/UpdateCommandHandler.java.ejs +53 -2
- package/templates/evaluate/report.html.ejs +1447 -90
- package/templates/kafka-event/KafkaConfigBean.java.ejs +1 -1
- package/templates/kafka-event/KafkaMessageBroker.java.ejs +3 -3
- package/templates/ports/PortAclMapper.java.ejs +35 -0
- package/templates/ports/PortFeignAdapter.java.ejs +7 -22
- package/templates/ports/PortFeignClient.java.ejs +4 -0
- package/templates/ports/PortResponseDto.java.ejs +1 -1
- package/templates/rabbitmq-event/RabbitConfigBean.java.ejs +33 -0
- package/templates/rabbitmq-event/RabbitConfigExchange.java.ejs +12 -0
- package/templates/rabbitmq-event/RabbitMessageBroker.java.ejs +35 -0
- package/templates/rabbitmq-event/RabbitMessageBrokerMethod.java.ejs +9 -0
- package/templates/rabbitmq-listener/RabbitConfigConsumerBean.java.ejs +33 -0
- package/templates/rabbitmq-listener/RabbitConfigConsumerExchange.java.ejs +12 -0
- package/templates/rabbitmq-listener/RabbitListenerClass.java.ejs +82 -0
- package/templates/rabbitmq-listener/RabbitListenerSimple.java.ejs +56 -0
- package/templates/read-model/ReadModelDomain.java.ejs +46 -0
- package/templates/read-model/ReadModelJpa.java.ejs +58 -0
- package/templates/read-model/ReadModelJpaRepository.java.ejs +13 -0
- package/templates/read-model/ReadModelKafkaListener.java.ejs +64 -0
- package/templates/read-model/ReadModelRabbitListener.java.ejs +71 -0
- package/templates/read-model/ReadModelRepository.java.ejs +42 -0
- package/templates/read-model/ReadModelRepositoryImpl.java.ejs +85 -0
- package/templates/read-model/ReadModelSyncHandler.java.ejs +54 -0
- package/templates/shared/configurations/kafkaConfig/KafkaConfig.java.ejs +18 -4
- package/templates/shared/configurations/rabbitmqConfig/RabbitMQConfig.java.ejs +100 -0
- package/templates/shared/configurations/temporalConfig/TemporalConfig.java.ejs +2 -64
- package/templates/shared/configurations/temporalConfig/TemporalWorkerFactoryLifecycle.java.ejs +41 -0
- package/templates/temporal-activity/ActivityImpl.java.ejs +68 -2
- package/templates/temporal-activity/ActivityInput.java.ejs +14 -0
- package/templates/temporal-activity/ActivityInterface.java.ejs +7 -1
- package/templates/temporal-activity/ActivityOutput.java.ejs +14 -0
- package/templates/temporal-activity/NestedType.java.ejs +12 -0
- package/templates/temporal-activity/SharedActivityInput.java.ejs +14 -0
- package/templates/temporal-activity/SharedActivityInterface.java.ejs +15 -0
- package/templates/temporal-activity/SharedActivityOutput.java.ejs +14 -0
- package/templates/temporal-activity/SharedNestedType.java.ejs +12 -0
- package/templates/temporal-flow/ModuleHeavyActivity.java.ejs +6 -0
- package/templates/temporal-flow/ModuleLightActivity.java.ejs +6 -0
- package/templates/temporal-flow/ModuleTemporalWorkerConfig.java.ejs +58 -0
- package/templates/temporal-flow/WorkFlowImpl.java.ejs +172 -12
- package/templates/temporal-flow/WorkFlowInput.java.ejs +11 -0
- package/templates/temporal-flow/WorkFlowInterface.java.ejs +5 -4
- package/templates/temporal-flow/WorkFlowService.java.ejs +42 -12
- package/COMMAND_EVALUATION.md +0 -911
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
package <%= packageName %>.<%= moduleName %>.infrastructure.rabbitListener;
|
|
2
|
+
<% const isUpsert = action === 'UPSERT'; %>
|
|
3
|
+
<% if (isUpsert) { %>
|
|
4
|
+
|
|
5
|
+
import <%= packageName %>.<%= moduleName %>.application.events.<%= integrationEventClassName %>;
|
|
6
|
+
<% } %>
|
|
7
|
+
import <%= packageName %>.<%= moduleName %>.application.usecases.<%= syncHandlerName %>;
|
|
8
|
+
import <%= packageName %>.shared.infrastructure.eventEnvelope.EventEnvelope;
|
|
9
|
+
|
|
10
|
+
import com.fasterxml.jackson.core.type.TypeReference;
|
|
11
|
+
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
12
|
+
import com.rabbitmq.client.Channel;
|
|
13
|
+
import org.springframework.amqp.core.Message;
|
|
14
|
+
import org.springframework.amqp.rabbit.annotation.RabbitListener;
|
|
15
|
+
import org.springframework.stereotype.Component;
|
|
16
|
+
|
|
17
|
+
import java.io.IOException;
|
|
18
|
+
import java.util.Map;
|
|
19
|
+
<% if (isUpsert) { %>
|
|
20
|
+
<% const needsBigDecimal = fields && fields.some(f => f.javaType === 'BigDecimal'); %>
|
|
21
|
+
<% const needsLocalDate = fields && fields.some(f => ['LocalDate','LocalDateTime','LocalTime'].includes(f.javaType)); %>
|
|
22
|
+
<% const needsInstant = fields && fields.some(f => f.javaType === 'Instant'); %>
|
|
23
|
+
<% const needsUUID = fields && fields.some(f => f.javaType === 'UUID'); %>
|
|
24
|
+
<% if (needsBigDecimal) { %>import java.math.BigDecimal;
|
|
25
|
+
<% } %><% if (needsLocalDate) { %>import java.time.LocalDate;
|
|
26
|
+
import java.time.LocalDateTime;
|
|
27
|
+
import java.time.LocalTime;
|
|
28
|
+
<% } %><% if (needsInstant) { %>import java.time.Instant;
|
|
29
|
+
<% } %><% if (needsUUID) { %>import java.util.UUID;
|
|
30
|
+
<% } %>
|
|
31
|
+
<% } %>
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* RabbitMQ listener for read model sync — queue: <%= topicConstant %>.
|
|
35
|
+
* Delegates to <%= syncHandlerName %>.on<%= eventBaseName %>().
|
|
36
|
+
*/
|
|
37
|
+
@Component("<%= moduleName %>.<%= listenerClassName %>")
|
|
38
|
+
public class <%= listenerClassName %> {
|
|
39
|
+
|
|
40
|
+
private final <%= syncHandlerName %> syncHandler;
|
|
41
|
+
private final ObjectMapper objectMapper;
|
|
42
|
+
|
|
43
|
+
public <%= listenerClassName %>(<%= syncHandlerName %> syncHandler, ObjectMapper objectMapper) {
|
|
44
|
+
this.syncHandler = syncHandler;
|
|
45
|
+
this.objectMapper = objectMapper;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
@RabbitListener(queues = "<%= topicSpringProperty %>")
|
|
49
|
+
public void handle(Message message, Channel channel) throws IOException {
|
|
50
|
+
EventEnvelope<Map<String, Object>> event = objectMapper.readValue(
|
|
51
|
+
message.getBody(),
|
|
52
|
+
new TypeReference<EventEnvelope<Map<String, Object>>>() {});
|
|
53
|
+
|
|
54
|
+
<% if (isUpsert) { %>
|
|
55
|
+
<% (fields || []).forEach(f => { %>
|
|
56
|
+
<%- f.javaType %> <%= f.name %> = objectMapper.convertValue(event.data().get("<%= f.payloadKey || f.name %>"), <%- f.javaType %>.class);
|
|
57
|
+
<% }); %>
|
|
58
|
+
|
|
59
|
+
syncHandler.on<%= eventBaseName %>(new <%= integrationEventClassName %>(
|
|
60
|
+
<% (fields || []).forEach((f, i) => { %>
|
|
61
|
+
<%= f.name %><%= i < fields.length - 1 ? ',' : '' %>
|
|
62
|
+
<% }); %>
|
|
63
|
+
));
|
|
64
|
+
<% } else { %>
|
|
65
|
+
String id = objectMapper.convertValue(event.data().get("<%= (fields[0] && fields[0].payloadKey) || 'id' %>"), String.class);
|
|
66
|
+
syncHandler.on<%= eventBaseName %>(id);
|
|
67
|
+
<% } %>
|
|
68
|
+
|
|
69
|
+
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
package <%= packageName %>.<%= moduleName %>.domain.repositories;
|
|
2
|
+
<% const needsBigDecimal = fields && fields.some(f => f.javaType === 'BigDecimal'); %>
|
|
3
|
+
<% const needsLocalDate = fields && fields.some(f => ['LocalDate','LocalDateTime','LocalTime'].includes(f.javaType)); %>
|
|
4
|
+
<% const needsInstant = fields && fields.some(f => f.javaType === 'Instant'); %>
|
|
5
|
+
<% const needsUUID = fields && fields.some(f => f.javaType === 'UUID'); %>
|
|
6
|
+
<% if (needsBigDecimal) { %>
|
|
7
|
+
import java.math.BigDecimal;
|
|
8
|
+
<% } %>
|
|
9
|
+
<% if (needsLocalDate) { %>
|
|
10
|
+
import java.time.LocalDate;
|
|
11
|
+
import java.time.LocalDateTime;
|
|
12
|
+
import java.time.LocalTime;
|
|
13
|
+
<% } %>
|
|
14
|
+
<% if (needsInstant) { %>
|
|
15
|
+
import java.time.Instant;
|
|
16
|
+
<% } %>
|
|
17
|
+
<% if (needsUUID) { %>
|
|
18
|
+
import java.util.UUID;
|
|
19
|
+
<% } %>
|
|
20
|
+
|
|
21
|
+
import <%= packageName %>.<%= moduleName %>.domain.models.readmodels.<%= domainClassName %>;
|
|
22
|
+
|
|
23
|
+
import java.util.Optional;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Repository interface for the <%= domainClassName %> read model.
|
|
27
|
+
* Provides read-only access and upsert/delete for event-driven sync.
|
|
28
|
+
*/
|
|
29
|
+
public interface <%= repositoryName %> {
|
|
30
|
+
|
|
31
|
+
void upsert(<%= domainClassName %> readModel);
|
|
32
|
+
|
|
33
|
+
void deleteById(String id);
|
|
34
|
+
<% if (hasSoftDelete) { %>
|
|
35
|
+
|
|
36
|
+
void softDeleteById(String id);
|
|
37
|
+
<% } %>
|
|
38
|
+
|
|
39
|
+
Optional<<%= domainClassName %>> findById(String id);
|
|
40
|
+
|
|
41
|
+
boolean existsById(String id);
|
|
42
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
package <%= packageName %>.<%= moduleName %>.infrastructure.database.repositories;
|
|
2
|
+
<% const needsBigDecimal = fields && fields.some(f => f.javaType === 'BigDecimal'); %>
|
|
3
|
+
<% const needsLocalDate = fields && fields.some(f => ['LocalDate','LocalDateTime','LocalTime'].includes(f.javaType)); %>
|
|
4
|
+
<% const needsInstant = fields && fields.some(f => f.javaType === 'Instant'); %>
|
|
5
|
+
<% const needsUUID = fields && fields.some(f => f.javaType === 'UUID'); %>
|
|
6
|
+
<% if (needsBigDecimal) { %>
|
|
7
|
+
import java.math.BigDecimal;
|
|
8
|
+
<% } %>
|
|
9
|
+
<% if (needsLocalDate || hasSoftDelete) { %>
|
|
10
|
+
import java.time.LocalDateTime;
|
|
11
|
+
<% } %>
|
|
12
|
+
<% if (needsInstant) { %>
|
|
13
|
+
import java.time.Instant;
|
|
14
|
+
<% } %>
|
|
15
|
+
<% if (needsUUID) { %>
|
|
16
|
+
import java.util.UUID;
|
|
17
|
+
<% } %>
|
|
18
|
+
|
|
19
|
+
import <%= packageName %>.<%= moduleName %>.domain.models.readmodels.<%= domainClassName %>;
|
|
20
|
+
import <%= packageName %>.<%= moduleName %>.domain.repositories.<%= repositoryName %>;
|
|
21
|
+
import <%= packageName %>.<%= moduleName %>.infrastructure.database.entities.<%= jpaEntityName %>;
|
|
22
|
+
import org.springframework.stereotype.Repository;
|
|
23
|
+
|
|
24
|
+
import java.util.Optional;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Repository implementation for the <%= domainClassName %> read model.
|
|
28
|
+
* Maps between domain read model and JPA entity.
|
|
29
|
+
*/
|
|
30
|
+
@Repository("<%= moduleName %>.<%= repositoryImplName %>")
|
|
31
|
+
public class <%= repositoryImplName %> implements <%= repositoryName %> {
|
|
32
|
+
|
|
33
|
+
private final <%= jpaRepositoryName %> jpaRepository;
|
|
34
|
+
|
|
35
|
+
public <%= repositoryImplName %>(<%= jpaRepositoryName %> jpaRepository) {
|
|
36
|
+
this.jpaRepository = jpaRepository;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
@Override
|
|
40
|
+
public void upsert(<%= domainClassName %> readModel) {
|
|
41
|
+
<%= jpaEntityName %> entity = jpaRepository.findById(readModel.getId())
|
|
42
|
+
.orElseGet(() -> {
|
|
43
|
+
<%= jpaEntityName %> newEntity = new <%= jpaEntityName %>();
|
|
44
|
+
newEntity.setId(readModel.getId());
|
|
45
|
+
return newEntity;
|
|
46
|
+
});
|
|
47
|
+
<% fields.filter(f => f.name !== 'id').forEach(field => { %>
|
|
48
|
+
entity.set<%= field.name.charAt(0).toUpperCase() + field.name.slice(1) %>(readModel.get<%= field.name.charAt(0).toUpperCase() + field.name.slice(1) %>());
|
|
49
|
+
<% }); %>
|
|
50
|
+
jpaRepository.save(entity);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
@Override
|
|
54
|
+
public void deleteById(String id) {
|
|
55
|
+
jpaRepository.deleteById(id);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
@Override
|
|
59
|
+
public Optional<<%= domainClassName %>> findById(String id) {
|
|
60
|
+
return jpaRepository.findById(id).map(this::toDomain);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
@Override
|
|
64
|
+
public boolean existsById(String id) {
|
|
65
|
+
return jpaRepository.existsById(id);
|
|
66
|
+
}
|
|
67
|
+
<% if (hasSoftDelete) { %>
|
|
68
|
+
|
|
69
|
+
@Override
|
|
70
|
+
public void softDeleteById(String id) {
|
|
71
|
+
jpaRepository.findById(id).ifPresent(entity -> {
|
|
72
|
+
entity.setDeletedAt(LocalDateTime.now());
|
|
73
|
+
jpaRepository.save(entity);
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
<% } %>
|
|
77
|
+
|
|
78
|
+
private <%= domainClassName %> toDomain(<%= jpaEntityName %> entity) {
|
|
79
|
+
return new <%= domainClassName %>(
|
|
80
|
+
<% fields.forEach((field, idx) => { %>
|
|
81
|
+
entity.get<%= field.name.charAt(0).toUpperCase() + field.name.slice(1) %>()<%= idx < fields.length - 1 ? ',' : '' %>
|
|
82
|
+
<% }); %>
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
package <%= packageName %>.<%= moduleName %>.application.usecases;
|
|
2
|
+
<% const upsertEntries = syncedBy.filter(s => s.action === 'UPSERT'); %>
|
|
3
|
+
<% const upsertImports = [...new Set(upsertEntries.map(s => s.integrationEventClassName))]; %>
|
|
4
|
+
<% upsertImports.forEach(cls => { %>
|
|
5
|
+
import <%= packageName %>.<%= moduleName %>.application.events.<%= cls %>;
|
|
6
|
+
<% }); %>
|
|
7
|
+
import <%= packageName %>.<%= moduleName %>.domain.models.readmodels.<%= domainClassName %>;
|
|
8
|
+
import <%= packageName %>.<%= moduleName %>.domain.repositories.<%= repositoryName %>;
|
|
9
|
+
import <%= packageName %>.shared.domain.annotations.ApplicationComponent;
|
|
10
|
+
import <%= packageName %>.shared.domain.annotations.LogExceptions;
|
|
11
|
+
import org.springframework.stereotype.Component;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Sync handler for the <%= domainClassName %> read model.
|
|
15
|
+
* Maintains the local projection by processing events from <%= sourceModule %>/<%= sourceName %>.
|
|
16
|
+
* <p>
|
|
17
|
+
* One method per syncedBy event — Kafka listeners delegate directly to these methods.
|
|
18
|
+
*/
|
|
19
|
+
@ApplicationComponent
|
|
20
|
+
@Component("<%= moduleName %>.<%= syncHandlerName %>")
|
|
21
|
+
public class <%= syncHandlerName %> {
|
|
22
|
+
|
|
23
|
+
private final <%= repositoryName %> repository;
|
|
24
|
+
|
|
25
|
+
public <%= syncHandlerName %>(<%= repositoryName %> repository) {
|
|
26
|
+
this.repository = repository;
|
|
27
|
+
}
|
|
28
|
+
<% syncedBy.forEach(sync => { %>
|
|
29
|
+
<% if (sync.action === 'UPSERT') { %>
|
|
30
|
+
|
|
31
|
+
@LogExceptions
|
|
32
|
+
public void on<%= sync.eventBaseName %>(<%= sync.integrationEventClassName %> event) {
|
|
33
|
+
<%= domainClassName %> model = new <%= domainClassName %>(
|
|
34
|
+
<% fields.forEach((field, idx) => { %>
|
|
35
|
+
event.<%= field.name %>()<%= idx < fields.length - 1 ? ',' : '' %>
|
|
36
|
+
<% }); %>
|
|
37
|
+
);
|
|
38
|
+
repository.upsert(model);
|
|
39
|
+
}
|
|
40
|
+
<% } else if (sync.action === 'DELETE') { %>
|
|
41
|
+
|
|
42
|
+
@LogExceptions
|
|
43
|
+
public void on<%= sync.eventBaseName %>(String id) {
|
|
44
|
+
repository.deleteById(id);
|
|
45
|
+
}
|
|
46
|
+
<% } else if (sync.action === 'SOFT_DELETE') { %>
|
|
47
|
+
|
|
48
|
+
@LogExceptions
|
|
49
|
+
public void on<%= sync.eventBaseName %>(String id) {
|
|
50
|
+
repository.softDeleteById(id);
|
|
51
|
+
}
|
|
52
|
+
<% } %>
|
|
53
|
+
<% }); %>
|
|
54
|
+
}
|
|
@@ -12,7 +12,7 @@ import org.springframework.kafka.core.KafkaTemplate;
|
|
|
12
12
|
import org.springframework.kafka.listener.ContainerProperties;
|
|
13
13
|
import org.springframework.kafka.listener.DeadLetterPublishingRecoverer;
|
|
14
14
|
import org.springframework.kafka.listener.DefaultErrorHandler;
|
|
15
|
-
import org.springframework.util.backoff.
|
|
15
|
+
import org.springframework.util.backoff.ExponentialBackOff;
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
@Configuration
|
|
@@ -20,11 +20,23 @@ import org.springframework.util.backoff.FixedBackOff;
|
|
|
20
20
|
public class KafkaConfig {
|
|
21
21
|
|
|
22
22
|
@Value("${spring.kafka.listener.retry.max-attempts}")
|
|
23
|
-
private
|
|
23
|
+
private int maxAttempts;
|
|
24
24
|
|
|
25
25
|
@Value("${spring.kafka.listener.retry.backoff-delay}")
|
|
26
26
|
private long backoffDelay;
|
|
27
27
|
|
|
28
|
+
@Value("${spring.kafka.listener.retry.backoff-multiplier:1.0}")
|
|
29
|
+
private double backoffMultiplier;
|
|
30
|
+
|
|
31
|
+
@Value("${spring.kafka.listener.retry.backoff-max-delay:30000}")
|
|
32
|
+
private long backoffMaxDelay;
|
|
33
|
+
|
|
34
|
+
@Value("${kafka.topic-defaults.partitions:3}")
|
|
35
|
+
private int defaultPartitions;
|
|
36
|
+
|
|
37
|
+
@Value("${kafka.topic-defaults.replicas:1}")
|
|
38
|
+
private short defaultReplicas;
|
|
39
|
+
|
|
28
40
|
@Bean
|
|
29
41
|
public ConcurrentKafkaListenerContainerFactory<String, String> kafkaListenerContainerFactory(
|
|
30
42
|
ConsumerFactory<String, String> consumerFactory,
|
|
@@ -39,8 +51,10 @@ public class KafkaConfig {
|
|
|
39
51
|
// Redirige al topic original + ".DLT"
|
|
40
52
|
(record, ex) -> new TopicPartition(record.topic() + ".DLT", record.partition())
|
|
41
53
|
);
|
|
42
|
-
// Configura reintentos
|
|
43
|
-
|
|
54
|
+
// Configura reintentos con backoff exponencial
|
|
55
|
+
ExponentialBackOff backOff = new ExponentialBackOff(backoffDelay, backoffMultiplier);
|
|
56
|
+
backOff.setMaxInterval(backoffMaxDelay);
|
|
57
|
+
backOff.setMaxAttempts(maxAttempts);
|
|
44
58
|
// Manejador de errores
|
|
45
59
|
DefaultErrorHandler errorHandler = new DefaultErrorHandler(recoverer, backOff);
|
|
46
60
|
factory.setCommonErrorHandler(errorHandler);
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
package <%= packageName %>.shared.infrastructure.configurations.rabbitmqConfig;
|
|
2
|
+
|
|
3
|
+
import org.springframework.amqp.core.*;
|
|
4
|
+
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
|
|
5
|
+
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
|
|
6
|
+
import org.springframework.amqp.rabbit.core.RabbitAdmin;
|
|
7
|
+
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
|
8
|
+
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
|
|
9
|
+
import org.springframework.amqp.support.converter.MessageConverter;
|
|
10
|
+
import org.springframework.beans.factory.annotation.Value;
|
|
11
|
+
import org.springframework.boot.ApplicationRunner;
|
|
12
|
+
import org.springframework.context.annotation.Bean;
|
|
13
|
+
import org.springframework.context.annotation.Configuration;
|
|
14
|
+
import org.springframework.amqp.rabbit.annotation.EnableRabbit;
|
|
15
|
+
import org.springframework.retry.backoff.ExponentialBackOffPolicy;
|
|
16
|
+
import org.springframework.retry.policy.SimpleRetryPolicy;
|
|
17
|
+
import org.springframework.retry.support.RetryTemplate;
|
|
18
|
+
import org.slf4j.Logger;
|
|
19
|
+
import org.slf4j.LoggerFactory;
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@Configuration
|
|
23
|
+
@EnableRabbit
|
|
24
|
+
public class RabbitMQConfig {
|
|
25
|
+
|
|
26
|
+
private static final Logger log = LoggerFactory.getLogger(RabbitMQConfig.class);
|
|
27
|
+
|
|
28
|
+
@Value("${spring.rabbitmq.listener.simple.retry.max-attempts}")
|
|
29
|
+
private int maxAttempts;
|
|
30
|
+
|
|
31
|
+
@Value("${spring.rabbitmq.listener.simple.retry.initial-interval}")
|
|
32
|
+
private long initialInterval;
|
|
33
|
+
|
|
34
|
+
@Value("${spring.rabbitmq.listener.simple.retry.multiplier:1.0}")
|
|
35
|
+
private double multiplier;
|
|
36
|
+
|
|
37
|
+
@Value("${spring.rabbitmq.listener.simple.retry.max-interval:10000}")
|
|
38
|
+
private long maxInterval;
|
|
39
|
+
|
|
40
|
+
@Bean
|
|
41
|
+
public MessageConverter jackson2JsonMessageConverter() {
|
|
42
|
+
return new Jackson2JsonMessageConverter();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
@Bean
|
|
46
|
+
public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory) {
|
|
47
|
+
return new RabbitAdmin(connectionFactory);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
@Bean
|
|
51
|
+
public ApplicationRunner rabbitInitializer(RabbitAdmin rabbitAdmin) {
|
|
52
|
+
return args -> rabbitAdmin.initialize();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
@Bean
|
|
56
|
+
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory,
|
|
57
|
+
MessageConverter jackson2JsonMessageConverter) {
|
|
58
|
+
RabbitTemplate template = new RabbitTemplate(connectionFactory);
|
|
59
|
+
template.setMessageConverter(jackson2JsonMessageConverter);
|
|
60
|
+
template.setMandatory(true);
|
|
61
|
+
template.setConfirmCallback((correlationData, ack, cause) -> {
|
|
62
|
+
if (!ack) {
|
|
63
|
+
log.error("Message not confirmed by broker: {}", cause);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
template.setReturnsCallback(returned -> {
|
|
67
|
+
log.error("Message returned — unroutable: exchange={}, routingKey={}, replyText={}",
|
|
68
|
+
returned.getExchange(), returned.getRoutingKey(), returned.getReplyText());
|
|
69
|
+
});
|
|
70
|
+
return template;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
@Bean
|
|
74
|
+
public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(
|
|
75
|
+
ConnectionFactory connectionFactory,
|
|
76
|
+
MessageConverter jackson2JsonMessageConverter) {
|
|
77
|
+
|
|
78
|
+
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
|
|
79
|
+
factory.setConnectionFactory(connectionFactory);
|
|
80
|
+
factory.setMessageConverter(jackson2JsonMessageConverter);
|
|
81
|
+
factory.setAcknowledgeMode(AcknowledgeMode.MANUAL);
|
|
82
|
+
factory.setDefaultRequeueRejected(false);
|
|
83
|
+
|
|
84
|
+
// Retry template with exponential backoff
|
|
85
|
+
RetryTemplate retryTemplate = new RetryTemplate();
|
|
86
|
+
SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy();
|
|
87
|
+
retryPolicy.setMaxAttempts(maxAttempts);
|
|
88
|
+
retryTemplate.setRetryPolicy(retryPolicy);
|
|
89
|
+
|
|
90
|
+
ExponentialBackOffPolicy backOffPolicy = new ExponentialBackOffPolicy();
|
|
91
|
+
backOffPolicy.setInitialInterval(initialInterval);
|
|
92
|
+
backOffPolicy.setMultiplier(multiplier);
|
|
93
|
+
backOffPolicy.setMaxInterval(maxInterval);
|
|
94
|
+
retryTemplate.setBackOffPolicy(backOffPolicy);
|
|
95
|
+
|
|
96
|
+
factory.setRetryTemplate(retryTemplate);
|
|
97
|
+
|
|
98
|
+
return factory;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -1,19 +1,12 @@
|
|
|
1
1
|
package <%= packageName %>.shared.infrastructure.configurations.temporalConfig;
|
|
2
2
|
|
|
3
|
-
import <%= packageName %>.shared.domain.interfaces.HeavyActivity;
|
|
4
|
-
import <%= packageName %>.shared.domain.interfaces.LightActivity;
|
|
5
3
|
import io.temporal.client.WorkflowClient;
|
|
6
4
|
import io.temporal.serviceclient.WorkflowServiceStubs;
|
|
7
|
-
import io.temporal.worker.Worker;
|
|
8
5
|
import io.temporal.worker.WorkerFactory;
|
|
9
|
-
import io.temporal.worker.WorkerOptions;
|
|
10
|
-
import jakarta.annotation.PreDestroy;
|
|
11
6
|
import org.springframework.beans.factory.annotation.Value;
|
|
12
7
|
import org.springframework.context.annotation.Bean;
|
|
13
8
|
import org.springframework.context.annotation.Configuration;
|
|
14
9
|
|
|
15
|
-
import java.util.List;
|
|
16
|
-
|
|
17
10
|
@Configuration
|
|
18
11
|
public class TemporalConfig {
|
|
19
12
|
|
|
@@ -23,26 +16,6 @@ public class TemporalConfig {
|
|
|
23
16
|
@Value("${temporal.namespace}")
|
|
24
17
|
private String namespace;
|
|
25
18
|
|
|
26
|
-
@Value("${temporal.flow-queue}")
|
|
27
|
-
private String flowQueue;
|
|
28
|
-
|
|
29
|
-
@Value("${temporal.number-flow-worker}")
|
|
30
|
-
private Integer numberFlowWorker;
|
|
31
|
-
|
|
32
|
-
@Value("${temporal.heavy-queue}")
|
|
33
|
-
private String heavyQueue;
|
|
34
|
-
|
|
35
|
-
@Value("${temporal.number-heavy-worker}")
|
|
36
|
-
private Integer numberHeavyWorker;
|
|
37
|
-
|
|
38
|
-
@Value("${temporal.light-queue}")
|
|
39
|
-
private String lightQueue;
|
|
40
|
-
|
|
41
|
-
@Value("${temporal.number-light-worker}")
|
|
42
|
-
private Integer numberLightWorker;
|
|
43
|
-
|
|
44
|
-
private WorkerFactory workerFactory;
|
|
45
|
-
|
|
46
19
|
@Bean
|
|
47
20
|
public WorkflowServiceStubs workflowServiceStubs() {
|
|
48
21
|
return WorkflowServiceStubs.newServiceStubs(
|
|
@@ -63,42 +36,7 @@ public class TemporalConfig {
|
|
|
63
36
|
}
|
|
64
37
|
|
|
65
38
|
@Bean
|
|
66
|
-
public WorkerFactory workerFactory(WorkflowClient client
|
|
67
|
-
|
|
68
|
-
List<LightActivity> lightActivities) {
|
|
69
|
-
|
|
70
|
-
workerFactory = WorkerFactory.newInstance(client);
|
|
71
|
-
|
|
72
|
-
// 1. WORKER DE FLUJO (Orquestador)
|
|
73
|
-
WorkerOptions workflowOptions = WorkerOptions.newBuilder()
|
|
74
|
-
.setMaxConcurrentWorkflowTaskExecutionSize(numberFlowWorker)
|
|
75
|
-
.build();
|
|
76
|
-
Worker workflowWorker = workerFactory.newWorker(flowQueue, workflowOptions);
|
|
77
|
-
// TODO: register your workflow implementation types here
|
|
78
|
-
// workflowWorker.registerWorkflowImplementationTypes(MyWorkflowImpl.class);
|
|
79
|
-
|
|
80
|
-
// 2. WORKER PESADO (tareas complejas)
|
|
81
|
-
WorkerOptions heavyOptions = WorkerOptions.newBuilder()
|
|
82
|
-
.setMaxConcurrentActivityExecutionSize(numberHeavyWorker)
|
|
83
|
-
.build();
|
|
84
|
-
Worker heavyWorker = workerFactory.newWorker(heavyQueue, heavyOptions);
|
|
85
|
-
heavyWorker.registerActivitiesImplementations(heavyActivities.toArray());
|
|
86
|
-
|
|
87
|
-
// 3. WORKER LIGERO (tareas rápidas)
|
|
88
|
-
WorkerOptions lightOptions = WorkerOptions.newBuilder()
|
|
89
|
-
.setMaxConcurrentActivityExecutionSize(numberLightWorker)
|
|
90
|
-
.build();
|
|
91
|
-
Worker lightWorker = workerFactory.newWorker(lightQueue, lightOptions);
|
|
92
|
-
lightWorker.registerActivitiesImplementations(lightActivities.toArray());
|
|
93
|
-
|
|
94
|
-
workerFactory.start();
|
|
95
|
-
return workerFactory;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
@PreDestroy
|
|
99
|
-
public void destroy() {
|
|
100
|
-
if (workerFactory != null) {
|
|
101
|
-
workerFactory.shutdown();
|
|
102
|
-
}
|
|
39
|
+
public WorkerFactory workerFactory(WorkflowClient client) {
|
|
40
|
+
return WorkerFactory.newInstance(client);
|
|
103
41
|
}
|
|
104
42
|
}
|
package/templates/shared/configurations/temporalConfig/TemporalWorkerFactoryLifecycle.java.ejs
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
package <%= packageName %>.shared.infrastructure.configurations.temporalConfig;
|
|
2
|
+
|
|
3
|
+
import io.temporal.worker.WorkerFactory;
|
|
4
|
+
import jakarta.annotation.PreDestroy;
|
|
5
|
+
import org.springframework.context.SmartLifecycle;
|
|
6
|
+
import org.springframework.stereotype.Component;
|
|
7
|
+
|
|
8
|
+
@Component
|
|
9
|
+
public class TemporalWorkerFactoryLifecycle implements SmartLifecycle {
|
|
10
|
+
|
|
11
|
+
private final WorkerFactory workerFactory;
|
|
12
|
+
private volatile boolean running = false;
|
|
13
|
+
|
|
14
|
+
public TemporalWorkerFactoryLifecycle(WorkerFactory workerFactory) {
|
|
15
|
+
this.workerFactory = workerFactory;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
@Override
|
|
19
|
+
public void start() {
|
|
20
|
+
workerFactory.start();
|
|
21
|
+
running = true;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
@Override
|
|
25
|
+
public void stop() {
|
|
26
|
+
if (workerFactory != null) {
|
|
27
|
+
workerFactory.shutdown();
|
|
28
|
+
}
|
|
29
|
+
running = false;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
@Override
|
|
33
|
+
public boolean isRunning() {
|
|
34
|
+
return running;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
@Override
|
|
38
|
+
public int getPhase() {
|
|
39
|
+
return Integer.MAX_VALUE;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -1,14 +1,80 @@
|
|
|
1
1
|
package <%= packageName %>.<%= moduleName %>.infrastructure.adapters.activities;
|
|
2
2
|
|
|
3
|
+
<% if (shared) { %>
|
|
4
|
+
import <%= packageName %>.shared.domain.contracts.<%= moduleName %>.<%= activityPascalCase %>Activity;
|
|
5
|
+
<% if (hasInput) { %>
|
|
6
|
+
import <%= packageName %>.shared.domain.contracts.<%= moduleName %>.<%= activityPascalCase %>Input;
|
|
7
|
+
<% } %>
|
|
8
|
+
<% if (hasOutput) { %>
|
|
9
|
+
import <%= packageName %>.shared.domain.contracts.<%= moduleName %>.<%= activityPascalCase %>Output;
|
|
10
|
+
<% } %>
|
|
11
|
+
<% } else { %>
|
|
3
12
|
import <%= packageName %>.<%= moduleName %>.application.ports.<%= activityPascalCase %>Activity;
|
|
4
|
-
|
|
13
|
+
<% if (hasInput) { %>
|
|
14
|
+
import <%= packageName %>.<%= moduleName %>.application.dtos.temporal.<%= activityPascalCase %>Input;
|
|
15
|
+
<% } %>
|
|
16
|
+
<% if (hasOutput) { %>
|
|
17
|
+
import <%= packageName %>.<%= moduleName %>.application.dtos.temporal.<%= activityPascalCase %>Output;
|
|
18
|
+
<% } %>
|
|
19
|
+
<% } %>
|
|
20
|
+
import <%= packageName %>.<%= moduleName %>.domain.interfaces.<%= activityCategory %>;
|
|
21
|
+
<% if (isQueryActivity && queryMeta) { %>
|
|
22
|
+
import <%= packageName %>.<%= moduleName %>.domain.models.entities.<%= queryMeta.aggregateName %>;
|
|
23
|
+
import <%= packageName %>.<%= moduleName %>.domain.repositories.<%= queryMeta.aggregateName %>Repository;
|
|
24
|
+
import <%= packageName %>.shared.domain.customExceptions.NotFoundException;
|
|
25
|
+
<% if (queryMeta.voMappingImports && queryMeta.voMappingImports.length > 0) { -%>
|
|
26
|
+
<% queryMeta.voMappingImports.forEach(imp => { -%>
|
|
27
|
+
<%- imp %>
|
|
28
|
+
<% }); -%>
|
|
29
|
+
<% } -%>
|
|
30
|
+
<% } %>
|
|
5
31
|
import org.springframework.stereotype.Component;
|
|
32
|
+
import org.springframework.transaction.annotation.Transactional;
|
|
6
33
|
|
|
7
34
|
@Component
|
|
8
35
|
public class <%= activityPascalCase %>ActivityImpl implements <%= activityPascalCase %>Activity, <%= activityCategory %> {
|
|
36
|
+
<% if (isQueryActivity && queryMeta) { %>
|
|
37
|
+
|
|
38
|
+
private final <%= queryMeta.aggregateName %>Repository repository;
|
|
39
|
+
|
|
40
|
+
public <%= activityPascalCase %>ActivityImpl(<%= queryMeta.aggregateName %>Repository repository) {
|
|
41
|
+
this.repository = repository;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
@Override
|
|
45
|
+
@Transactional(readOnly = true)
|
|
46
|
+
public <%= activityPascalCase %>Output execute(<%= activityPascalCase %>Input input) {
|
|
47
|
+
<% const findMethod = (queryMeta.needsEagerLoad && queryMeta.eagerLoadField)
|
|
48
|
+
? 'findByIdWith' + queryMeta.eagerLoadField.fieldPascal
|
|
49
|
+
: 'findById'; -%>
|
|
50
|
+
<%= queryMeta.aggregateName %> entity = repository.<%= findMethod %>(<%= queryMeta.idFieldAccessor %>)
|
|
51
|
+
.orElseThrow(() -> new NotFoundException("<%= queryMeta.aggregateName %> not found with id: " + <%= queryMeta.idFieldAccessor %>));
|
|
52
|
+
<% if (queryMeta.outputMappings.some(m => m.preDeclaration)) { -%>
|
|
53
|
+
<% queryMeta.outputMappings.filter(m => m.preDeclaration).forEach(m => { %>
|
|
54
|
+
<%- m.preDeclaration.varType %> <%- m.preDeclaration.varName %> = <%- m.preDeclaration.getter %> != null
|
|
55
|
+
? new <%- m.preDeclaration.varType %>(
|
|
56
|
+
<% m.preDeclaration.ntArgs.forEach((arg, ai) => { -%>
|
|
57
|
+
<%- arg %><%= ai < m.preDeclaration.ntArgs.length - 1 ? ',' : '' %>
|
|
58
|
+
<% }); -%>
|
|
59
|
+
)
|
|
60
|
+
: null;
|
|
61
|
+
<% }); -%>
|
|
62
|
+
<% } -%>
|
|
63
|
+
return new <%= activityPascalCase %>Output(
|
|
64
|
+
<% queryMeta.outputMappings.forEach((m, i) => { -%>
|
|
65
|
+
<%- m.accessor %><%= i < queryMeta.outputMappings.length - 1 ? ',' : '' %>
|
|
66
|
+
<% }); -%>
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
<% } else { %>
|
|
9
70
|
|
|
10
71
|
@Override
|
|
11
|
-
|
|
72
|
+
@Transactional
|
|
73
|
+
public <%= hasOutput ? activityPascalCase + 'Output' : 'void' %> execute(<%= hasInput ? activityPascalCase + 'Input input' : '' %>) {
|
|
12
74
|
//todo: implement the logic
|
|
75
|
+
<% if (hasOutput) { %>
|
|
76
|
+
throw new UnsupportedOperationException("Not implemented yet");
|
|
77
|
+
<% } %>
|
|
13
78
|
}
|
|
79
|
+
<% } %>
|
|
14
80
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
package <%= packageName %>.<%= moduleName %>.application.dtos.temporal;
|
|
2
|
+
<%
|
|
3
|
+
const _allImports = [...(imports || []), ...((typeof nestedTypeImportLines !== 'undefined' ? nestedTypeImportLines : []) || [])];
|
|
4
|
+
if (_allImports.length > 0) { %>
|
|
5
|
+
|
|
6
|
+
<%= _allImports.join('\n') %>
|
|
7
|
+
<% } %>
|
|
8
|
+
|
|
9
|
+
public record <%= activityPascalCase %>Input(
|
|
10
|
+
<% inputFields.forEach((field, index) => { %>
|
|
11
|
+
<%- field.javaType %> <%= field.name %><%= index < inputFields.length - 1 ? ',' : '' %>
|
|
12
|
+
<% }); %>
|
|
13
|
+
) {
|
|
14
|
+
}
|
|
@@ -2,10 +2,16 @@ package <%= packageName %>.<%= moduleName %>.application.ports;
|
|
|
2
2
|
|
|
3
3
|
import io.temporal.activity.ActivityInterface;
|
|
4
4
|
import io.temporal.activity.ActivityMethod;
|
|
5
|
+
<% if (hasInput) { %>
|
|
6
|
+
import <%= packageName %>.<%= moduleName %>.application.dtos.temporal.<%= activityPascalCase %>Input;
|
|
7
|
+
<% } %>
|
|
8
|
+
<% if (hasOutput) { %>
|
|
9
|
+
import <%= packageName %>.<%= moduleName %>.application.dtos.temporal.<%= activityPascalCase %>Output;
|
|
10
|
+
<% } %>
|
|
5
11
|
|
|
6
12
|
@ActivityInterface
|
|
7
13
|
public interface <%= activityPascalCase %>Activity {
|
|
8
14
|
|
|
9
15
|
@ActivityMethod(name = "<%= activityPascalCase %>")
|
|
10
|
-
void execute(
|
|
16
|
+
<%= hasOutput ? activityPascalCase + 'Output' : 'void' %> execute(<%= hasInput ? activityPascalCase + 'Input input' : '' %>);
|
|
11
17
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
package <%= packageName %>.<%= moduleName %>.application.dtos.temporal;
|
|
2
|
+
<%
|
|
3
|
+
const _allImports = [...(imports || []), ...((typeof nestedTypeImportLines !== 'undefined' ? nestedTypeImportLines : []) || [])];
|
|
4
|
+
if (_allImports.length > 0) { %>
|
|
5
|
+
|
|
6
|
+
<%= _allImports.join('\n') %>
|
|
7
|
+
<% } %>
|
|
8
|
+
|
|
9
|
+
public record <%= activityPascalCase %>Output(
|
|
10
|
+
<% outputFields.forEach((field, index) => { %>
|
|
11
|
+
<%- field.javaType %> <%= field.name %><%= index < outputFields.length - 1 ? ',' : '' %>
|
|
12
|
+
<% }); %>
|
|
13
|
+
) {
|
|
14
|
+
}
|