diff --git a/process-driven-approach-showcase/applicant-employee-application/pom.xml b/process-driven-approach-showcase/applicant-employee-application/pom.xml index 8b3cbac..3e5fe2d 100644 --- a/process-driven-approach-showcase/applicant-employee-application/pom.xml +++ b/process-driven-approach-showcase/applicant-employee-application/pom.xml @@ -17,4 +17,76 @@ UTF-8 - \ No newline at end of file + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-websocket + + + org.springframework.boot + spring-boot-starter-webflux + + + io.camunda + spring-zeebe-starter + ${camunda8.version} + + + org.webjars + webjars-locator-core + + + org.webjars + sockjs-client + 1.5.1 + + + org.webjars + stomp-websocket + 2.3.4 + + + + + org.springframework.kafka + spring-kafka + + + + + io.miragon.miranum + worker-api + ${miranum.version} + + + io.miragon.miranum + process-api + ${miranum.version} + + + io.miragon.miranum + message-api + ${miranum.version} + + + io.miragon.miranum + worker-adapter-c8 + ${miranum.version} + + + io.miragon.miranum + process-adapter-c8 + ${miranum.version} + + + io.miragon.miranum + message-adapter-c8 + ${miranum.version} + + + + diff --git a/process-driven-approach-showcase/applicant-employee-application/src/main/java/applicant/employee/application/Applicant2EmployeeApplication.java b/process-driven-approach-showcase/applicant-employee-application/src/main/java/applicant/employee/application/Applicant2EmployeeApplication.java new file mode 100644 index 0000000..29ddff5 --- /dev/null +++ b/process-driven-approach-showcase/applicant-employee-application/src/main/java/applicant/employee/application/Applicant2EmployeeApplication.java @@ -0,0 +1,15 @@ +package applicant.employee.application; + +import io.camunda.zeebe.spring.client.annotation.Deployment; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +@Deployment(resources = "classpath*:**/restaurant-miranum.bpmn") +public class Applicant2EmployeeApplication { + public static void main(String[] args) { + SpringApplication.run(Applicant2EmployeeApplication.class, args); + } +} + + diff --git a/process-driven-approach-showcase/applicant-employee-application/src/main/java/applicant/employee/application/adapter/in/rest/ApplicationController.java b/process-driven-approach-showcase/applicant-employee-application/src/main/java/applicant/employee/application/adapter/in/rest/ApplicationController.java new file mode 100644 index 0000000..6274f2c --- /dev/null +++ b/process-driven-approach-showcase/applicant-employee-application/src/main/java/applicant/employee/application/adapter/in/rest/ApplicationController.java @@ -0,0 +1,34 @@ +package applicant.employee.application.adapter.in.rest; + +import applicant.employee.application.adapter.in.rest.dtos.PlaceApplicationRequestDto; +import applicant.employee.application.adapter.in.rest.dtos.PlaceApplicationResponseDto; +import applicant.employee.application.application.port.in.PlaceApplicationInCommand; +import applicant.employee.application.application.port.in.PlaceApplicationUseCase; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@Slf4j +@AllArgsConstructor +public class ApplicationController { + private final PlaceApplicationUseCase placeApplicationUseCase; + + @PostMapping + @RequestMapping("/order") + public ResponseEntity placeOrder(@RequestBody PlaceApplicationRequestDto placeApplicationRequestDto) { + var placeApplicationInCommand = new PlaceApplicationInCommand(placeApplicationRequestDto); + String applicationId = placeApplicationUseCase.placeApplication(placeApplicationInCommand); + String message = String.format("Thanks for submitting the request! We'll work on hiring %s for the position %s!", + placeApplicationRequestDto.getApplicantName(), + placeApplicationRequestDto.getPosition()); + + log.info("[{}] {}", applicationId, message); + return new ResponseEntity<>(new PlaceApplicationResponseDto(applicationId, message), HttpStatus.CREATED); + } +} diff --git a/process-driven-approach-showcase/applicant-employee-application/src/main/java/applicant/employee/application/adapter/in/rest/dtos/PlaceApplicationRequestDto.java b/process-driven-approach-showcase/applicant-employee-application/src/main/java/applicant/employee/application/adapter/in/rest/dtos/PlaceApplicationRequestDto.java new file mode 100644 index 0000000..963e246 --- /dev/null +++ b/process-driven-approach-showcase/applicant-employee-application/src/main/java/applicant/employee/application/adapter/in/rest/dtos/PlaceApplicationRequestDto.java @@ -0,0 +1,15 @@ +package applicant.employee.application.adapter.in.rest.dtos; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +public class PlaceApplicationRequestDto { + private String applicantName; + private String applicantAddress; + private String applicantPhone; + private String position; +} diff --git a/process-driven-approach-showcase/applicant-employee-application/src/main/java/applicant/employee/application/adapter/in/rest/dtos/PlaceApplicationResponseDto.java b/process-driven-approach-showcase/applicant-employee-application/src/main/java/applicant/employee/application/adapter/in/rest/dtos/PlaceApplicationResponseDto.java new file mode 100644 index 0000000..a46d52a --- /dev/null +++ b/process-driven-approach-showcase/applicant-employee-application/src/main/java/applicant/employee/application/adapter/in/rest/dtos/PlaceApplicationResponseDto.java @@ -0,0 +1,14 @@ +package applicant.employee.application.adapter.in.rest.dtos; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +public class PlaceApplicationResponseDto { + private String applicationId; + private String message; + +} diff --git a/process-driven-approach-showcase/applicant-employee-application/src/main/java/applicant/employee/application/adapter/out/camunda/MessageAdapter.java b/process-driven-approach-showcase/applicant-employee-application/src/main/java/applicant/employee/application/adapter/out/camunda/MessageAdapter.java new file mode 100644 index 0000000..4a3a31d --- /dev/null +++ b/process-driven-approach-showcase/applicant-employee-application/src/main/java/applicant/employee/application/adapter/out/camunda/MessageAdapter.java @@ -0,0 +1,38 @@ +package applicant.employee.application.adapter.out.camunda; + +import applicant.employee.application.application.port.out.placeApplication.PlaceApplicationOutCommand; +import applicant.employee.application.application.port.out.placeApplication.PlaceApplicationOutPort; +import io.miragon.miranum.connect.message.api.CorrelateMessageCommand; +import io.miragon.miranum.connect.message.api.MessageApi; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.Map; + +@Slf4j +@AllArgsConstructor +@Component +public class MessageAdapter implements PlaceApplicationOutPort { + private final MessageApi messageApi; + private static final String MESSAGE_REFERENCE = "Message_offer_made"; + + @Override + public void placeApplication(PlaceApplicationOutCommand placeApplicationOutCommand) { + Map variables = new HashMap<>(); + variables.put("applicationId", placeApplicationOutCommand.getApplication().getApplicationId()); + variables.put("applicantName", placeApplicationOutCommand.getApplication().getApplicantName()); + variables.put("applicantPhone", placeApplicationOutCommand.getApplication().getApplicantPhone()); + variables.put("applicantAddress", placeApplicationOutCommand.getApplication().getApplicantAddress()); + variables.put("applicantCity", placeApplicationOutCommand.getApplication().getPosition()); + + messageApi.correlateMessage(new CorrelateMessageCommand( + MESSAGE_REFERENCE, + placeApplicationOutCommand.getApplication().getApplicationId(), + variables)); + log.info("[{}] Sent '{}'-Message to Process Engine.", + placeApplicationOutCommand.getApplication().getApplicationId(), + MESSAGE_REFERENCE); + } +} diff --git a/process-driven-approach-showcase/applicant-employee-application/src/main/java/applicant/employee/application/adapter/out/websocket/WebsocketConfig.java b/process-driven-approach-showcase/applicant-employee-application/src/main/java/applicant/employee/application/adapter/out/websocket/WebsocketConfig.java new file mode 100644 index 0000000..cc62fba --- /dev/null +++ b/process-driven-approach-showcase/applicant-employee-application/src/main/java/applicant/employee/application/adapter/out/websocket/WebsocketConfig.java @@ -0,0 +1,23 @@ +package applicant.employee.application.adapter.out.websocket; + +import org.springframework.context.annotation.Configuration; +import org.springframework.messaging.simp.config.MessageBrokerRegistry; +import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; +import org.springframework.web.socket.config.annotation.StompEndpointRegistry; +import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer; + +@Configuration +@EnableWebSocketMessageBroker +public class WebsocketConfig implements WebSocketMessageBrokerConfigurer { + + @Override + public void configureMessageBroker(MessageBrokerRegistry config) { + config.enableSimpleBroker("/topic"); + } + + @Override + public void registerStompEndpoints(StompEndpointRegistry registry) { + registry.addEndpoint("/application").withSockJS(); + } + +} diff --git a/process-driven-approach-showcase/applicant-employee-application/src/main/java/applicant/employee/application/adapter/out/websocket/WebsocketNotificator.java b/process-driven-approach-showcase/applicant-employee-application/src/main/java/applicant/employee/application/adapter/out/websocket/WebsocketNotificator.java new file mode 100644 index 0000000..5a3f21e --- /dev/null +++ b/process-driven-approach-showcase/applicant-employee-application/src/main/java/applicant/employee/application/adapter/out/websocket/WebsocketNotificator.java @@ -0,0 +1,22 @@ +package applicant.employee.application.adapter.out.websocket; + +import applicant.employee.application.application.port.out.formFeedback.FormFeedbackOutCommand; +import applicant.employee.application.application.port.out.formFeedback.FormFeedbackOutPort; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.messaging.simp.SimpMessageSendingOperations; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +@AllArgsConstructor +public class WebsocketNotificator implements FormFeedbackOutPort { + + private SimpMessageSendingOperations messagingTemplate; + + @Override + public void propagateFeedback(FormFeedbackOutCommand formFeedbackOutCommand) { + log.info("[{}] Notifying Customer: {}", formFeedbackOutCommand.getApplicationId(), formFeedbackOutCommand.getMessage()); + messagingTemplate.convertAndSend(String.format("/topic/message/%s", formFeedbackOutCommand.getApplicationId()), formFeedbackOutCommand.getMessage()); + } +} diff --git a/process-driven-approach-showcase/applicant-employee-application/src/main/java/applicant/employee/application/application/port/in/PlaceApplicationInCommand.java b/process-driven-approach-showcase/applicant-employee-application/src/main/java/applicant/employee/application/application/port/in/PlaceApplicationInCommand.java new file mode 100644 index 0000000..3cc0029 --- /dev/null +++ b/process-driven-approach-showcase/applicant-employee-application/src/main/java/applicant/employee/application/application/port/in/PlaceApplicationInCommand.java @@ -0,0 +1,19 @@ +package applicant.employee.application.application.port.in; + +import applicant.employee.application.adapter.in.rest.dtos.PlaceApplicationRequestDto; +import lombok.Getter; + +@Getter +public class PlaceApplicationInCommand { + private final String applicantName; + private final String applicantAddress; + private final String applicantPhone; + private final String position; + + public PlaceApplicationInCommand(PlaceApplicationRequestDto placeApplicationInCommand) { + this.applicantName = placeApplicationInCommand.getApplicantName(); + this.applicantAddress = placeApplicationInCommand.getApplicantAddress(); + this.applicantPhone = placeApplicationInCommand.getApplicantPhone(); + this.position = placeApplicationInCommand.getPosition(); + } +} diff --git a/process-driven-approach-showcase/applicant-employee-application/src/main/java/applicant/employee/application/application/port/in/PlaceApplicationUseCase.java b/process-driven-approach-showcase/applicant-employee-application/src/main/java/applicant/employee/application/application/port/in/PlaceApplicationUseCase.java new file mode 100644 index 0000000..b1ac4fb --- /dev/null +++ b/process-driven-approach-showcase/applicant-employee-application/src/main/java/applicant/employee/application/application/port/in/PlaceApplicationUseCase.java @@ -0,0 +1,5 @@ +package applicant.employee.application.application.port.in; + +public interface PlaceApplicationUseCase { + String placeApplication(PlaceApplicationInCommand placeApplicationInCommand); +} diff --git a/process-driven-approach-showcase/applicant-employee-application/src/main/java/applicant/employee/application/application/port/out/formFeedback/FormFeedbackOutCommand.java b/process-driven-approach-showcase/applicant-employee-application/src/main/java/applicant/employee/application/application/port/out/formFeedback/FormFeedbackOutCommand.java new file mode 100644 index 0000000..1d2d890 --- /dev/null +++ b/process-driven-approach-showcase/applicant-employee-application/src/main/java/applicant/employee/application/application/port/out/formFeedback/FormFeedbackOutCommand.java @@ -0,0 +1,13 @@ +package applicant.employee.application.application.port.out.formFeedback; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +public class FormFeedbackOutCommand { + private String applicationId; + private String message; +} diff --git a/process-driven-approach-showcase/applicant-employee-application/src/main/java/applicant/employee/application/application/port/out/formFeedback/FormFeedbackOutPort.java b/process-driven-approach-showcase/applicant-employee-application/src/main/java/applicant/employee/application/application/port/out/formFeedback/FormFeedbackOutPort.java new file mode 100644 index 0000000..928f9f2 --- /dev/null +++ b/process-driven-approach-showcase/applicant-employee-application/src/main/java/applicant/employee/application/application/port/out/formFeedback/FormFeedbackOutPort.java @@ -0,0 +1,5 @@ +package applicant.employee.application.application.port.out.formFeedback; + +public interface FormFeedbackOutPort { + void propagateFeedback(FormFeedbackOutCommand formFeedbackOutCommand); +} diff --git a/process-driven-approach-showcase/applicant-employee-application/src/main/java/applicant/employee/application/application/port/out/placeApplication/PlaceApplicationOutCommand.java b/process-driven-approach-showcase/applicant-employee-application/src/main/java/applicant/employee/application/application/port/out/placeApplication/PlaceApplicationOutCommand.java new file mode 100644 index 0000000..0f4dfef --- /dev/null +++ b/process-driven-approach-showcase/applicant-employee-application/src/main/java/applicant/employee/application/application/port/out/placeApplication/PlaceApplicationOutCommand.java @@ -0,0 +1,13 @@ +package applicant.employee.application.application.port.out.placeApplication; + +import applicant.employee.application.domain.Application; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +public class PlaceApplicationOutCommand { + private Application application; +} diff --git a/process-driven-approach-showcase/applicant-employee-application/src/main/java/applicant/employee/application/application/port/out/placeApplication/PlaceApplicationOutPort.java b/process-driven-approach-showcase/applicant-employee-application/src/main/java/applicant/employee/application/application/port/out/placeApplication/PlaceApplicationOutPort.java new file mode 100644 index 0000000..5629dd3 --- /dev/null +++ b/process-driven-approach-showcase/applicant-employee-application/src/main/java/applicant/employee/application/application/port/out/placeApplication/PlaceApplicationOutPort.java @@ -0,0 +1,6 @@ +package applicant.employee.application.application.port.out.placeApplication; + +public interface PlaceApplicationOutPort { + + void placeApplication(PlaceApplicationOutCommand placeApplicationOutCommand); +} diff --git a/process-driven-approach-showcase/applicant-employee-application/src/main/java/applicant/employee/application/application/service/PlaceApplicationService.java b/process-driven-approach-showcase/applicant-employee-application/src/main/java/applicant/employee/application/application/service/PlaceApplicationService.java new file mode 100644 index 0000000..439585c --- /dev/null +++ b/process-driven-approach-showcase/applicant-employee-application/src/main/java/applicant/employee/application/application/service/PlaceApplicationService.java @@ -0,0 +1,23 @@ +package applicant.employee.application.application.service; + +import applicant.employee.application.application.port.in.PlaceApplicationInCommand; +import applicant.employee.application.application.port.in.PlaceApplicationUseCase; +import applicant.employee.application.application.port.out.placeApplication.PlaceApplicationOutCommand; +import applicant.employee.application.application.port.out.placeApplication.PlaceApplicationOutPort; +import applicant.employee.application.domain.Application; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class PlaceApplicationService implements PlaceApplicationUseCase { + private final PlaceApplicationOutPort placeApplicationPort; + + @Override + public String placeApplication(PlaceApplicationInCommand placeApplicationInCommand) { + var application = new Application(placeApplicationInCommand); + var placeOrderOutCommand = new PlaceApplicationOutCommand(application); + placeApplicationPort.placeApplication(placeOrderOutCommand); + return application.getApplicationId(); + } +} diff --git a/process-driven-approach-showcase/applicant-employee-application/src/main/java/applicant/employee/application/domain/Application.java b/process-driven-approach-showcase/applicant-employee-application/src/main/java/applicant/employee/application/domain/Application.java new file mode 100644 index 0000000..9ed3660 --- /dev/null +++ b/process-driven-approach-showcase/applicant-employee-application/src/main/java/applicant/employee/application/domain/Application.java @@ -0,0 +1,23 @@ +package applicant.employee.application.domain; + +import applicant.employee.application.application.port.in.PlaceApplicationInCommand; +import lombok.Getter; + +import java.time.LocalDateTime; + +@Getter +public class Application { + private final String applicantName; + private final String applicantAddress; + private final String applicantPhone; + private final String position; + private final String applicationId; + + public Application(PlaceApplicationInCommand placeApplicationInCommand) { + this.applicantName = placeApplicationInCommand.getApplicantName(); + this.applicantAddress = placeApplicationInCommand.getApplicantAddress(); + this.applicantPhone = placeApplicationInCommand.getApplicantPhone(); + this.position = placeApplicationInCommand.getPosition(); + this.applicationId = String.format("order-%s-%s", placeApplicationInCommand.getApplicantName().toLowerCase().replaceAll("\\s", ""), LocalDateTime.now());; + } +} diff --git a/process-driven-approach-showcase/applicant-employee-application/src/main/resources/application.yaml b/process-driven-approach-showcase/applicant-employee-application/src/main/resources/application.yaml new file mode 100644 index 0000000..82c98ca --- /dev/null +++ b/process-driven-approach-showcase/applicant-employee-application/src/main/resources/application.yaml @@ -0,0 +1,17 @@ +server: + port: 8883 + +application: + kafka: + enabled: true + +zeebe.client: + broker: + gateway-address: localhost:26500 + security: + plaintext: true + +spring.kafka.producer: + bootstrap-servers: localhost:9092 + key-serializer: org.apache.kafka.common.serialization.StringSerializer + value-serializer: org.springframework.kafka.support.serializer.JsonSerializer diff --git a/process-driven-approach-showcase/hr-system-service-contract-application/src/main/resources/hr-system-service-contract-layer.bpmn b/process-driven-approach-showcase/hr-system-service-contract-application/src/main/resources/hr-system-service-contract-layer.bpmn new file mode 100644 index 0000000..4ed328c --- /dev/null +++ b/process-driven-approach-showcase/hr-system-service-contract-application/src/main/resources/hr-system-service-contract-layer.bpmn @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/process-driven-approach-showcase/payroll-service-contract-application/src/main/resources/payroll-service-contract-layer.bpmn b/process-driven-approach-showcase/payroll-service-contract-application/src/main/resources/payroll-service-contract-layer.bpmn new file mode 100644 index 0000000..cb2a3c3 --- /dev/null +++ b/process-driven-approach-showcase/payroll-service-contract-application/src/main/resources/payroll-service-contract-layer.bpmn @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + +