Skip to content

Commit

Permalink
GRAD2-2648 (#341)
Browse files Browse the repository at this point in the history
* GRAD2-2637 - Cache institute api data into Redis

* GRAD2-2637 - Cache institute api data into Redis

* GRAD2-2637 - Cache institute api data into Redis

* GRAD2-2637 - Cache institute api data into Redis

* GRAD2-2637 - Cache institute api data into Redis

* GRAD2-2637 - Cache institute api data into Redis

* GRAD2-2637 - Cache institute api data into Redis

* GRAD2-2637 - Cache institute api data into Redis

* GRAD2-2637 - Cache institute api data into Redis

* GRAD2-2637 - Cache institute api data into Redis

* GRAD2-2637 - Cache institute api data into Redis

* GRAD2-2637 - Cache institute api data into Redis

* GRAD2-2637 - Cache institute api data into Redis

* GRAD2-2637 - Cache institute api data into Redis

* GRAD2-2637 - Cache institute api data into Redis

* GRAD2-2637 - Cache institute api data into Redis

* GRAD2-2637 - Cache institute api data into Redis

* GRAD2-2637 - Cache institute api data into Redis

* GRAD2-2637 - Cache institute api data into Redis

* GRAD2-2637 - Cache institute api data into Redis

* GRAD2-2637 - Cache institute api data into Redis

* GRAD2-2637 - Cache institute api data into Redis

* GRAD2-2637 - Cache institute api data into Redis

* GRAD2-2637 - Cache institute api data into Redis

* GRAD2-2637 - Cache institute api data into Redis

* GRAD2-2637 - Cache institute api data into Redis

* GRAD2-2637 - Cache institute api data into Redis

* GRAD2-2637 - Cache institute api data into Redis

* GRAD2-2637 - Cache institute api data into Redis

* GRAD2-2637 - Cache institute api data into Redis

* GRAD2-2637 - Cache institute api data into Redis

* GRAD2-2637 - Cache institute api data into Redis

* GRAD2-2637 - Cache institute api data into Redis

* Commit to save

* Ignoring application-local.yaml

* Changed Event to EventEntity for clarity

* Added EventHistoryEntity

* Added EventHistoryRepository

* Implemented add to history

* Fixed unit test

* Added more coverage.

* Fixing maintainability

* Added school updated and supporting unit tests.

* Added school updated and supporting unit tests.

* Added school created and supporting unit tests.

* Added school moved and supporting unit tests.

* Added update district and supporting tests

* Added missing property

* Correctly transforming to entity here.

* Updated unit testing

* Finalizing unit testing and move school.

* Forgot to add these files.

* Fixing Test Coverage.

* Fixing duplication of code.

---------

Co-authored-by: Kamal Mohammed <[email protected]>
Co-authored-by: chris.ditcher <[email protected]>
  • Loading branch information
3 people authored Aug 8, 2024
1 parent a9f6478 commit cfa0b16
Show file tree
Hide file tree
Showing 57 changed files with 1,087 additions and 164 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,6 @@ build/

### VS Code ###
.vscode/

### local dev ###
application-local.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@
import ca.bc.gov.educ.api.trax.model.dto.DistrictContact;
import ca.bc.gov.educ.api.trax.model.dto.GradStatusEventPayloadDTO;
import ca.bc.gov.educ.api.trax.model.dto.SchoolContact;
import ca.bc.gov.educ.api.trax.model.entity.Event;
import ca.bc.gov.educ.api.trax.model.dto.institute.District;
import ca.bc.gov.educ.api.trax.model.dto.institute.MoveSchoolData;
import ca.bc.gov.educ.api.trax.model.dto.institute.School;
import ca.bc.gov.educ.api.trax.model.entity.EventEntity;
import ca.bc.gov.educ.api.trax.repository.EventRepository;
import ca.bc.gov.educ.api.trax.service.EventService;
import ca.bc.gov.educ.api.trax.util.JsonUtil;
Expand Down Expand Up @@ -48,74 +51,90 @@ public ChoreographEventHandler(final List<EventService> eventServices, final Eve
eventServices.forEach(eventService -> this.eventServiceMap.put(eventService.getEventType(), eventService));
}

public void handleEvent(@NonNull final Event event) {
public void handleEvent(@NonNull final EventEntity eventEntity) {
//only one thread will process all the request. since RDB won't handle concurrent requests.
this.eventExecutor.execute(() -> {
try {
switch (EventType.valueOf(event.getEventType())) {
switch (EventType.valueOf(eventEntity.getEventType())) {
case GRAD_STUDENT_GRADUATED -> {
log.debug("Processing GRAD_STUDENT_GRADUATED event record :: {} ", event);
val studentGraduated = JsonUtil.getJsonObjectFromString(GradStatusEventPayloadDTO.class, event.getEventPayload());
this.eventServiceMap.get(GRAD_STUDENT_GRADUATED.toString()).processEvent(studentGraduated, event);
log.debug("Processing GRAD_STUDENT_GRADUATED eventEntity record :: {} ", eventEntity);
val studentGraduated = JsonUtil.getJsonObjectFromString(GradStatusEventPayloadDTO.class, eventEntity.getEventPayload());
this.eventServiceMap.get(GRAD_STUDENT_GRADUATED.toString()).processEvent(studentGraduated, eventEntity);
}
case GRAD_STUDENT_UPDATED -> {
log.debug("Processing GRAD_STUDENT_UPDATED event record :: {} ", event);
val studentUpdated = JsonUtil.getJsonObjectFromString(GradStatusEventPayloadDTO.class, event.getEventPayload());
this.eventServiceMap.get(GRAD_STUDENT_UPDATED.toString()).processEvent(studentUpdated, event);
log.debug("Processing GRAD_STUDENT_UPDATED eventEntity record :: {} ", eventEntity);
val studentUpdated = JsonUtil.getJsonObjectFromString(GradStatusEventPayloadDTO.class, eventEntity.getEventPayload());
this.eventServiceMap.get(GRAD_STUDENT_UPDATED.toString()).processEvent(studentUpdated, eventEntity);
}
case GRAD_STUDENT_UNDO_COMPLETION -> {
log.debug("Processing GRAD_STUDENT_UNDO_COMPLETION event record :: {} ", event);
val studentUndoCompletion = JsonUtil.getJsonObjectFromString(GradStatusEventPayloadDTO.class, event.getEventPayload());
this.eventServiceMap.get(GRAD_STUDENT_UNDO_COMPLETION.toString()).processEvent(studentUndoCompletion, event);
log.debug("Processing GRAD_STUDENT_UNDO_COMPLETION eventEntity record :: {} ", eventEntity);
val studentUndoCompletion = JsonUtil.getJsonObjectFromString(GradStatusEventPayloadDTO.class, eventEntity.getEventPayload());
this.eventServiceMap.get(GRAD_STUDENT_UNDO_COMPLETION.toString()).processEvent(studentUndoCompletion, eventEntity);
}
case CREATE_SCHOOL_CONTACT -> {
log.debug("Processing {} event record :: {} ", event.getEventType(), event);
val schoolContactCreated = JsonUtil.getJsonObjectFromString(SchoolContact.class, event.getEventPayload());
this.eventServiceMap.get(CREATE_SCHOOL_CONTACT.toString()).processEvent(schoolContactCreated, event);
log.debug("Processing {} eventEntity record :: {} ", eventEntity.getEventType(), eventEntity);
val schoolContactCreated = JsonUtil.getJsonObjectFromString(SchoolContact.class, eventEntity.getEventPayload());
this.eventServiceMap.get(CREATE_SCHOOL_CONTACT.toString()).processEvent(schoolContactCreated, eventEntity);
}
case UPDATE_SCHOOL_CONTACT -> {
log.debug("Processing {} event record :: {} ", event.getEventType(), event);
val schoolContactUpdated = JsonUtil.getJsonObjectFromString(SchoolContact.class, event.getEventPayload());
this.eventServiceMap.get(UPDATE_SCHOOL_CONTACT.toString()).processEvent(schoolContactUpdated, event);
log.debug("Processing {} eventEntity record :: {} ", eventEntity.getEventType(), eventEntity);
val schoolContactUpdated = JsonUtil.getJsonObjectFromString(SchoolContact.class, eventEntity.getEventPayload());
this.eventServiceMap.get(UPDATE_SCHOOL_CONTACT.toString()).processEvent(schoolContactUpdated, eventEntity);
}
case DELETE_SCHOOL_CONTACT -> {
log.debug("Processing {} event record :: {} ", event.getEventType(), event);
val schoolContactDeleted = JsonUtil.getJsonObjectFromString(SchoolContact.class, event.getEventPayload());
this.eventServiceMap.get(DELETE_SCHOOL_CONTACT.toString()).processEvent(schoolContactDeleted, event);
log.debug("Processing {} eventEntity record :: {} ", eventEntity.getEventType(), eventEntity);
val schoolContactDeleted = JsonUtil.getJsonObjectFromString(SchoolContact.class, eventEntity.getEventPayload());
this.eventServiceMap.get(DELETE_SCHOOL_CONTACT.toString()).processEvent(schoolContactDeleted, eventEntity);
}
case CREATE_AUTHORITY_CONTACT -> {
log.debug("Processing {} event record :: {} ", event.getEventType(), event);
val authorityContactCreated = JsonUtil.getJsonObjectFromString(AuthorityContact.class, event.getEventPayload());
this.eventServiceMap.get(CREATE_AUTHORITY_CONTACT.toString()).processEvent(authorityContactCreated, event);
log.debug("Processing {} eventEntity record :: {} ", eventEntity.getEventType(), eventEntity);
val authorityContactCreated = JsonUtil.getJsonObjectFromString(AuthorityContact.class, eventEntity.getEventPayload());
this.eventServiceMap.get(CREATE_AUTHORITY_CONTACT.toString()).processEvent(authorityContactCreated, eventEntity);
}
case UPDATE_AUTHORITY_CONTACT -> {
log.debug("Processing {} event record :: {} ", event.getEventType(), event);
val authorityContactUpdated = JsonUtil.getJsonObjectFromString(AuthorityContact.class, event.getEventPayload());
this.eventServiceMap.get(UPDATE_AUTHORITY_CONTACT.toString()).processEvent(authorityContactUpdated, event);
log.debug("Processing {} eventEntity record :: {} ", eventEntity.getEventType(), eventEntity);
val authorityContactUpdated = JsonUtil.getJsonObjectFromString(AuthorityContact.class, eventEntity.getEventPayload());
this.eventServiceMap.get(UPDATE_AUTHORITY_CONTACT.toString()).processEvent(authorityContactUpdated, eventEntity);
}
case DELETE_AUTHORITY_CONTACT -> {
log.debug("Processing {} event record :: {} ", event.getEventType(), event);
val authorityContactDeleted = JsonUtil.getJsonObjectFromString(AuthorityContact.class, event.getEventPayload());
this.eventServiceMap.get(DELETE_AUTHORITY_CONTACT.toString()).processEvent(authorityContactDeleted, event);
log.debug("Processing {} eventEntity record :: {} ", eventEntity.getEventType(), eventEntity);
val authorityContactDeleted = JsonUtil.getJsonObjectFromString(AuthorityContact.class, eventEntity.getEventPayload());
this.eventServiceMap.get(DELETE_AUTHORITY_CONTACT.toString()).processEvent(authorityContactDeleted, eventEntity);
}
case CREATE_DISTRICT_CONTACT -> {
log.debug("Processing {} event record :: {} ", event.getEventType(), event);
val districtContactCreated = JsonUtil.getJsonObjectFromString(DistrictContact.class, event.getEventPayload());
this.eventServiceMap.get(CREATE_DISTRICT_CONTACT.toString()).processEvent(districtContactCreated, event);
log.debug("Processing {} eventEntity record :: {} ", eventEntity.getEventType(), eventEntity);
val districtContactCreated = JsonUtil.getJsonObjectFromString(DistrictContact.class, eventEntity.getEventPayload());
this.eventServiceMap.get(CREATE_DISTRICT_CONTACT.toString()).processEvent(districtContactCreated, eventEntity);
}
case UPDATE_DISTRICT_CONTACT -> {
log.debug("Processing {} event record :: {} ", event.getEventType(), event);
val districtContactUpdated = JsonUtil.getJsonObjectFromString(DistrictContact.class, event.getEventPayload());
this.eventServiceMap.get(UPDATE_DISTRICT_CONTACT.toString()).processEvent(districtContactUpdated, event);
log.debug("Processing {} eventEntity record :: {} ", eventEntity.getEventType(), eventEntity);
val districtContactUpdated = JsonUtil.getJsonObjectFromString(DistrictContact.class, eventEntity.getEventPayload());
this.eventServiceMap.get(UPDATE_DISTRICT_CONTACT.toString()).processEvent(districtContactUpdated, eventEntity);
}
case DELETE_DISTRICT_CONTACT -> {
log.debug("Processing {} event record :: {} ", event.getEventType(), event);
val districtContactDeleted = JsonUtil.getJsonObjectFromString(DistrictContact.class, event.getEventPayload());
this.eventServiceMap.get(DELETE_DISTRICT_CONTACT.toString()).processEvent(districtContactDeleted, event);
log.debug("Processing {} eventEntity record :: {} ", eventEntity.getEventType(), eventEntity);
val districtContactDeleted = JsonUtil.getJsonObjectFromString(DistrictContact.class, eventEntity.getEventPayload());
this.eventServiceMap.get(DELETE_DISTRICT_CONTACT.toString()).processEvent(districtContactDeleted, eventEntity);
}
case UPDATE_SCHOOL -> {
val schoolUpdated = JsonUtil.getJsonObjectFromString(School.class, eventEntity.getEventPayload());
this.eventServiceMap.get(UPDATE_SCHOOL.toString()).processEvent(schoolUpdated, eventEntity);
}
case CREATE_SCHOOL -> {
val schoolCreated = JsonUtil.getJsonObjectFromString(School.class, eventEntity.getEventPayload());
this.eventServiceMap.get(CREATE_SCHOOL.toString()).processEvent(schoolCreated, eventEntity);
}
case MOVE_SCHOOL -> {
val schoolMoved = JsonUtil.getJsonObjectFromString(MoveSchoolData.class, eventEntity.getEventPayload());
this.eventServiceMap.get(MOVE_SCHOOL.toString()).processEvent(schoolMoved, eventEntity);
}
case UPDATE_DISTRICT -> {
val districtUpdated = JsonUtil.getJsonObjectFromString(District.class, eventEntity.getEventPayload());
this.eventServiceMap.get(UPDATE_DISTRICT.toString()).processEvent(districtUpdated, eventEntity);
}
default -> {
log.warn("Silently ignoring event: {}", event);
this.eventRepository.findByEventId(event.getEventId()).ifPresent(existingEvent -> {
log.warn("Silently ignoring eventEntity: {}", eventEntity);
this.eventRepository.findByEventId(eventEntity.getEventId()).ifPresent(existingEvent -> {
existingEvent.setEventStatus(EventStatus.PROCESSED.toString());
existingEvent.setUpdateDate(LocalDateTime.now());
this.eventRepository.save(existingEvent);
Expand All @@ -124,7 +143,7 @@ public void handleEvent(@NonNull final Event event) {
}
}
} catch (final Exception exception) {
log.error("Exception while processing event :: {}", event, exception);
log.error("Exception while processing eventEntity :: {}", eventEntity, exception);
}
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package ca.bc.gov.educ.api.trax.constant;

/**
* The enum Event outcome.
* The enum EventEntity outcome.
*/
public enum EventOutcome {
/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package ca.bc.gov.educ.api.trax.constant;

/**
* The enum Event status.
* The enum EventEntity status.
*/
public enum EventStatus {
/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package ca.bc.gov.educ.api.trax.constant;

/**
* The enum Event type.
* The enum EventEntity type.
*/
public enum EventType {
/* ===========================================================
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,5 @@ public List<SchoolDetail> getAllSchoolDetails() {
return schoolService.getSchoolDetailsFromRedisCache();
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import lombok.Getter;

public enum BusinessError {
EVENT_ALREADY_PERSISTED("Event with event id :: $? , is already persisted in DB, a duplicate message from Jet Stream.");
EVENT_ALREADY_PERSISTED("EventEntity with event id :: $? , is already persisted in DB, a duplicate message from Jet Stream.");

@Getter
private final String code;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ public void dispatchChoreographyEvent(final TraxUpdatedPubEvent traxUpdatedPubEv
try {
log.debug("Broadcasting replicationEvent :: {}", choreographedEvent);
val pub = this.jetStream.publishAsync(TRAX_UPDATE_EVENT_TOPIC.name(), JsonUtil.getJsonBytesFromObject(choreographedEvent));
pub.thenAcceptAsync(result -> log.debug("Event ID :: {} Published to JetStream :: {}", traxUpdatedPubEvent.getEventId(), result.getSeqno()));
pub.thenAcceptAsync(result -> log.debug("EventEntity ID :: {} Published to JetStream :: {}", traxUpdatedPubEvent.getEventId(), result.getSeqno()));
} catch (IOException e) {
log.error("exception while broadcasting message to JetStream", e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,19 @@
public class ChoreographedEvent {
UUID eventID;
/**
* The Event type.
* The EventEntity type.
*/
EventType eventType;
/**
* The Event outcome.
* The EventEntity outcome.
*/
EventOutcome eventOutcome;
/**
* The Activity code.
*/
String activityCode;
/**
* The Event payload.
* The EventEntity payload.
*/
String eventPayload; // json string
/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
package ca.bc.gov.educ.api.trax.model.dto.institute;

import ca.bc.gov.educ.api.trax.model.dto.BaseModel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.springframework.stereotype.Component;

import java.util.List;

@Data
@EqualsAndHashCode(callSuper = true)
@Component("InstituteDistrict")
@NoArgsConstructor
@AllArgsConstructor
public class District extends BaseModel {

private String districtId;
Expand All @@ -18,6 +22,7 @@ public class District extends BaseModel {
private String phoneNumber;
private String email;
private String website;
private String displayName;
private String districtRegionCode;
private String districtStatusCode;
private List<DistrictContact> contacts;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package ca.bc.gov.educ.api.trax.model.dto.institute;

import ca.bc.gov.educ.api.trax.model.dto.BaseModel;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import lombok.*;

import java.io.Serializable;

@EqualsAndHashCode(callSuper = true)
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
public class MoveSchoolData extends BaseModel implements Serializable {

/**
* The constant serialVersionUID.
*/
private static final long serialVersionUID = 1L;

@NotNull(message = "toSchool cannot be null.")
@Valid
private School toSchool;

@NotNull(message = "fromSchoolId cannot be null.")
private String fromSchoolId;

@NotNull(message = "moveDate cannot be null.")
private String moveDate;
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package ca.bc.gov.educ.api.trax.model.dto.institute;

import ca.bc.gov.educ.api.trax.model.dto.BaseModel;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.stereotype.Component;

@Data
@EqualsAndHashCode(callSuper = true)
@Component("InstituteSchool")
@JsonIgnoreProperties(ignoreUnknown = true)
public class School extends BaseModel {

private String schoolId;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,8 @@

import ca.bc.gov.educ.api.trax.model.dto.BaseModel;
import ca.bc.gov.educ.api.trax.model.dto.SchoolContact;
import ca.bc.gov.educ.api.trax.model.entity.institute.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.data.annotation.Id;
import org.springframework.data.redis.core.index.Indexed;
import org.springframework.stereotype.Component;

import java.util.List;
Expand Down Expand Up @@ -35,10 +32,6 @@ public class SchoolDetail extends BaseModel {
private String closedDate;
private boolean canIssueTranscripts;
private boolean canIssueCertificates;
private String createUser;
private String updateUser;
private String createDate;
private String updateDate;
List<SchoolContact> contacts;
List<SchoolAddress> addresses;
List<Note> notes;
Expand Down
Loading

0 comments on commit cfa0b16

Please sign in to comment.