Skip to content

Commit

Permalink
Merge pull request #13 from bcgov/feature/EAC-19
Browse files Browse the repository at this point in the history
Feature/eac 19
  • Loading branch information
arcshiftsolutions authored Oct 21, 2024
2 parents b072d2d + 5a23c83 commit e91352c
Show file tree
Hide file tree
Showing 11 changed files with 327 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ public enum EventOutcome {
INITIATE_SUCCESS,
STUDENT_REGISTRATION_FOUND,
STUDENT_REGISTRATION_NOT_FOUND,
STUDENT_REGISTRATION_CREATED,
STUDENT_REGISTRATION_PUBLISHED,
SAGA_COMPLETED,
STUDENT_ALREADY_EXIST
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ public enum EventType {
MARK_SAGA_COMPLETE, //Default. Used by BaseOrchestrator.
GET_PAGINATED_SCHOOLS,
CREATE_STUDENT_REGISTRATION,
GET_STUDENT_REGISTRATION
GET_STUDENT_REGISTRATION,
PUBLISH_STUDENT_REGISTRATION
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
package ca.bc.gov.educ.eas.api.constants;

public enum SagaEnum {

CREATE_STUDENT_REGISTRATION
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ public enum TopicsEnum {
EAS_API_TOPIC,
INSTITUTE_API_TOPIC,
EAS_EVENTS_TOPIC,
CREATE_STUDENT_REGISTRATION_SAGA_TOPIC
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package ca.bc.gov.educ.eas.api.orchestrator;

import ca.bc.gov.educ.eas.api.constants.SagaEnum;
import ca.bc.gov.educ.eas.api.constants.SagaStatusEnum;
import ca.bc.gov.educ.eas.api.constants.TopicsEnum;
import ca.bc.gov.educ.eas.api.messaging.MessagePublisher;
import ca.bc.gov.educ.eas.api.model.v1.EasSagaEntity;
import ca.bc.gov.educ.eas.api.model.v1.SagaEventStatesEntity;
import ca.bc.gov.educ.eas.api.orchestrator.base.BaseOrchestrator;
import ca.bc.gov.educ.eas.api.service.v1.StudentRegistrationOrchestrationService;
import ca.bc.gov.educ.eas.api.service.v1.SagaService;
import ca.bc.gov.educ.eas.api.struct.Event;
import ca.bc.gov.educ.eas.api.struct.v1.AssessmentStudent;
import ca.bc.gov.educ.eas.api.util.JsonUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import static ca.bc.gov.educ.eas.api.constants.EventType.CREATE_STUDENT_REGISTRATION;
import static ca.bc.gov.educ.eas.api.constants.EventType.PUBLISH_STUDENT_REGISTRATION;

import static ca.bc.gov.educ.eas.api.constants.EventOutcome.STUDENT_REGISTRATION_CREATED;
import static ca.bc.gov.educ.eas.api.constants.EventOutcome.STUDENT_REGISTRATION_PUBLISHED;


@Component
@Slf4j
public class StudentRegistrationOrchestrator extends BaseOrchestrator<AssessmentStudent> {

private final StudentRegistrationOrchestrationService studentRegistrationOrchestrationService;

protected StudentRegistrationOrchestrator(final SagaService sagaService, final MessagePublisher messagePublisher, StudentRegistrationOrchestrationService studentRegistrationOrchestrationService) {
super(sagaService, messagePublisher, AssessmentStudent.class, SagaEnum.CREATE_STUDENT_REGISTRATION.toString(), TopicsEnum.CREATE_STUDENT_REGISTRATION_SAGA_TOPIC.toString());
this.studentRegistrationOrchestrationService = studentRegistrationOrchestrationService;
}

@Override
public void populateStepsToExecuteMap() {
this.stepBuilder()
.begin(CREATE_STUDENT_REGISTRATION, this::createStudentRegistration)
.step(CREATE_STUDENT_REGISTRATION, STUDENT_REGISTRATION_CREATED, PUBLISH_STUDENT_REGISTRATION, this::publishStudentRegistration)
.end(PUBLISH_STUDENT_REGISTRATION, STUDENT_REGISTRATION_PUBLISHED);
}

private void createStudentRegistration(Event event, EasSagaEntity saga, AssessmentStudent sagaData) throws JsonProcessingException {
final SagaEventStatesEntity eventStates = this.createEventState(saga, event.getEventType(), event.getEventOutcome(), event.getEventPayload());
saga.setSagaState(CREATE_STUDENT_REGISTRATION.toString());
saga.setStatus(SagaStatusEnum.IN_PROGRESS.toString());
this.getSagaService().updateAttachedSagaWithEvents(saga, eventStates);
//Service call
studentRegistrationOrchestrationService.createNewStudentRegistration(sagaData);
final Event nextEvent = Event.builder().sagaId(saga.getSagaId())
.eventType(CREATE_STUDENT_REGISTRATION)
.eventOutcome(STUDENT_REGISTRATION_CREATED)
.eventPayload(JsonUtil.getJsonStringFromObject(sagaData))
.build();
this.postMessageToTopic(this.getTopicToSubscribe(), nextEvent);
logMessage(nextEvent, saga);
}

private void publishStudentRegistration(Event event, EasSagaEntity saga, AssessmentStudent sagaData) throws JsonProcessingException {
final SagaEventStatesEntity eventStates = this.createEventState(saga, event.getEventType(), event.getEventOutcome(), event.getEventPayload());
saga.setSagaState(PUBLISH_STUDENT_REGISTRATION.toString());
saga.setStatus(SagaStatusEnum.IN_PROGRESS.toString());
this.getSagaService().updateAttachedSagaWithEvents(saga, eventStates);
//Service call
studentRegistrationOrchestrationService.publishStudentRegistration(sagaData, saga);

final Event nextEvent = Event.builder().sagaId(saga.getSagaId())
.eventType(PUBLISH_STUDENT_REGISTRATION).eventOutcome(STUDENT_REGISTRATION_PUBLISHED)
.eventPayload(JsonUtil.getJsonStringFromObject(sagaData))
.build();
this.postMessageToTopic(this.getTopicToSubscribe(), nextEvent);
logMessage(nextEvent, saga);
}

private void logMessage(Event event, EasSagaEntity saga) {
log.debug("message sent to {} for {} Event. :: {}", this.getTopicToSubscribe(), event, saga.getSagaId());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.Optional;
import java.util.UUID;

@Service
Expand All @@ -37,6 +38,10 @@ public AssessmentStudentEntity getStudentByID(UUID assessmentStudentID) {
);
}

public Optional<AssessmentStudentEntity> getStudentByAssessmentIDAndStudentID(UUID assessmentID, UUID studentID) {
return assessmentStudentRepository.findByAssessmentEntity_AssessmentIDAndStudentID(assessmentID, studentID);
}

@Transactional(propagation = Propagation.REQUIRES_NEW)
public AssessmentStudentEntity updateStudent(AssessmentStudentEntity assessmentStudentEntity) {
AssessmentStudentEntity currentAssessmentStudentEntity = assessmentStudentRepository.findById(assessmentStudentEntity.getAssessmentStudentID()).orElseThrow(() ->
Expand All @@ -50,7 +55,8 @@ public AssessmentStudentEntity updateStudent(AssessmentStudentEntity assessmentS

@Transactional(propagation = Propagation.REQUIRES_NEW)
public AssessmentStudentEntity createStudent(AssessmentStudentEntity assessmentStudentEntity) {
return createAssessmentStudentWithHistory(assessmentStudentEntity);
Optional<AssessmentStudentEntity> studentEntity = assessmentStudentRepository.findByAssessmentEntity_AssessmentIDAndStudentID(assessmentStudentEntity.getAssessmentEntity().getAssessmentID(), assessmentStudentEntity.getStudentID());
return studentEntity.orElseGet(() -> createAssessmentStudentWithHistory(assessmentStudentEntity));
}

public AssessmentStudentEntity createAssessmentStudentWithHistory(AssessmentStudentEntity assessmentStudentEntity) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package ca.bc.gov.educ.eas.api.service.v1;

import ca.bc.gov.educ.eas.api.mappers.v1.AssessmentStudentMapper;
import ca.bc.gov.educ.eas.api.model.v1.AssessmentStudentEntity;
import ca.bc.gov.educ.eas.api.model.v1.EasSagaEntity;
import ca.bc.gov.educ.eas.api.struct.v1.AssessmentStudent;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.Optional;
import java.util.UUID;

@Service
@Slf4j
public class StudentRegistrationOrchestrationService {

private static final AssessmentStudentMapper mapper = AssessmentStudentMapper.mapper;
protected final SagaService sagaService;

@Getter(AccessLevel.PRIVATE)
private final AssessmentStudentService assessmentStudentService;

public StudentRegistrationOrchestrationService(AssessmentStudentService assessmentStudentService, SagaService sagaService) {
this.assessmentStudentService = assessmentStudentService;
this.sagaService = sagaService;
}

public void createNewStudentRegistration(AssessmentStudent assessmentStudent) {
Optional<AssessmentStudentEntity> studentEntity = assessmentStudentService.getStudentByAssessmentIDAndStudentID(UUID.fromString(assessmentStudent.getAssessmentID()), UUID.fromString(assessmentStudent.getStudentID()));
if (studentEntity.isEmpty()) {
assessmentStudentService.createStudent(mapper.toModel(assessmentStudent));
} else {
log.info("Student already exists in assessment {} ", assessmentStudent);
}
}

public void publishStudentRegistration(AssessmentStudent assessmentStudent, EasSagaEntity sagaEntity) {
//Placeholder
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ public EventHandlerDelegatorService(MessagePublisher messagePublisher, EventHand
*/
public void handleEvent(final Event event, final Message message) {
byte[] response;
Pair<byte[], EasEventEntity> pair;
boolean isSynchronous = message.getReplyTo() != null;
try {
switch (event.getEventType()) {
Expand All @@ -66,10 +65,9 @@ public void handleEvent(final Event event, final Message message) {
case CREATE_STUDENT_REGISTRATION:
log.info("received create student event :: {}", event.getSagaId());
log.trace(PAYLOAD_LOG, event.getEventPayload());
pair = eventHandlerService.handleCreateStudentRegistrationEvent(event);
response = eventHandlerService.handleCreateStudentRegistrationEvent(event);
log.info(RESPONDING_BACK_TO_NATS_ON_CHANNEL, message.getReplyTo() != null ? message.getReplyTo() : event.getReplyTo());
publishToNATS(event, message, isSynchronous, pair.getLeft());
publishToJetStream(pair.getRight());
publishToNATS(event, message, isSynchronous, response);
break;
default:
log.info("silently ignoring other events :: {}", event);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
import ca.bc.gov.educ.eas.api.constants.EventType;
import ca.bc.gov.educ.eas.api.mappers.v1.AssessmentStudentMapper;
import ca.bc.gov.educ.eas.api.model.v1.EasEventEntity;
import ca.bc.gov.educ.eas.api.orchestrator.StudentRegistrationOrchestrator;
import ca.bc.gov.educ.eas.api.repository.v1.AssessmentStudentRepository;
import ca.bc.gov.educ.eas.api.repository.v1.EasEventRepository;
import ca.bc.gov.educ.eas.api.service.v1.AssessmentStudentService;
import ca.bc.gov.educ.eas.api.struct.Event;
import ca.bc.gov.educ.eas.api.struct.v1.AssessmentStudent;
import ca.bc.gov.educ.eas.api.struct.v1.AssessmentStudentGet;
Expand All @@ -15,7 +15,7 @@
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
Expand Down Expand Up @@ -55,32 +55,24 @@ public class EventHandlerService {

private final AssessmentStudentRepository assessmentStudentRepository;

private final AssessmentStudentService assessmentStudentService;
private final StudentRegistrationOrchestrator studentRegistrationOrchestrator;

private static final AssessmentStudentMapper assessmentStudentMapper = AssessmentStudentMapper.mapper;

private final EasEventRepository easEventRepository;

@Transactional(propagation = Propagation.REQUIRES_NEW)
public Pair<byte[], EasEventEntity> handleCreateStudentRegistrationEvent(Event event) throws JsonProcessingException {
val studentEventOptional = easEventRepository.findBySagaIdAndEventType(event.getSagaId(), event.getEventType().toString());
EasEventEntity easEvent;
EasEventEntity choreographyEvent = null;
public byte[] handleCreateStudentRegistrationEvent(final Event event) throws JsonProcessingException {
final val studentEventOptional = easEventRepository.findBySagaIdAndEventType(event.getSagaId(), event.getEventType().toString());
if (studentEventOptional.isEmpty()) {
log.info(NO_RECORD_SAGA_ID_EVENT_TYPE);
log.trace(EVENT_PAYLOAD, event);
AssessmentStudent student = JsonUtil.getJsonObjectFromString(AssessmentStudent.class, event.getEventPayload());
val optionalStudent = assessmentStudentRepository.findByAssessmentEntity_AssessmentIDAndStudentID(UUID.fromString(student.getAssessmentID()), UUID.fromString(student.getStudentID()));
easEvent = createAssessmentStudentEventRecord(event);
final AssessmentStudent student = JsonUtil.getJsonObjectFromString(AssessmentStudent.class, event.getEventPayload());
val saga = studentRegistrationOrchestrator.createSaga(event.getEventPayload(), student.getUpdateUser());
studentRegistrationOrchestrator.startSaga(saga);
} else {
log.info(RECORD_FOUND_FOR_SAGA_ID_EVENT_TYPE);
log.trace(EVENT_PAYLOAD, event);
easEvent = studentEventOptional.get();
easEvent.setUpdateDate(LocalDateTime.now());
log.trace("Execution is not required for this message returning EVENT is :: {}", event);
}

easEventRepository.save(easEvent);
return Pair.of(createResponseEvent(easEvent), choreographyEvent);
return JsonUtil.getJsonBytesFromObject(ResponseEntity.ok());
}


Expand Down
2 changes: 2 additions & 0 deletions api/src/test/java/ca/bc/gov/educ/eas/api/BaseEasAPITest.java
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ public AssessmentStudent createMockStudent() {
.studentID(UUID.randomUUID().toString())
.pen("120164447")
.localID("123")
.createUser("ABC")
.updateUser("ABC")
.build();
}

Expand Down
Loading

0 comments on commit e91352c

Please sign in to comment.