Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: DBC / LocalOffice Programme owner refactor #469

Merged
merged 3 commits into from
Jul 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ plugins {
}

group = "uk.nhs.hee.tis.trainee"
version = "1.16.0"
version = "1.17.0"

configurations {
compileOnly {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@

package uk.nhs.hee.tis.trainee.sync.event;

import static uk.nhs.hee.tis.trainee.sync.event.LocalOfficeEventListener.LOCAL_OFFICE_NAME;

import java.util.Optional;
import java.util.Set;
import lombok.extern.slf4j.Slf4j;
Expand All @@ -33,10 +35,12 @@
import org.springframework.data.mongodb.core.mapping.event.BeforeDeleteEvent;
import org.springframework.stereotype.Component;
import uk.nhs.hee.tis.trainee.sync.model.Dbc;
import uk.nhs.hee.tis.trainee.sync.model.LocalOffice;
import uk.nhs.hee.tis.trainee.sync.model.Operation;
import uk.nhs.hee.tis.trainee.sync.model.Programme;
import uk.nhs.hee.tis.trainee.sync.service.DbcSyncService;
import uk.nhs.hee.tis.trainee.sync.service.FifoMessagingService;
import uk.nhs.hee.tis.trainee.sync.service.LocalOfficeSyncService;
import uk.nhs.hee.tis.trainee.sync.service.ProgrammeSyncService;

/**
Expand All @@ -47,10 +51,12 @@
public class DbcEventListener extends AbstractMongoEventListener<Dbc> {

public static final String DBC_NAME = "name";
public static final String DBC_ABBR = "abbr";

private final DbcSyncService dbcSyncService;

private final ProgrammeSyncService programmeSyncService;
private final LocalOfficeSyncService localOfficeSyncService;

private final FifoMessagingService fifoMessagingService;

Expand All @@ -59,11 +65,13 @@ public class DbcEventListener extends AbstractMongoEventListener<Dbc> {
private final Cache cache;

DbcEventListener(DbcSyncService dbcSyncService, ProgrammeSyncService programmeService,
LocalOfficeSyncService localOfficeSyncService,
FifoMessagingService fifoMessagingService,
@Value("${application.aws.sqs.programme}") String programmeQueueUrl,
CacheManager cacheManager) {
this.dbcSyncService = dbcSyncService;
this.programmeSyncService = programmeService;
this.localOfficeSyncService = localOfficeSyncService;
this.fifoMessagingService = fifoMessagingService;
this.programmeQueueUrl = programmeQueueUrl;
cache = cacheManager.getCache(Dbc.ENTITY_NAME);
Expand Down Expand Up @@ -115,25 +123,29 @@ public void onAfterDelete(AfterDeleteEvent<Dbc> event) {
* @param dbc The DBC to get related programmes for.
*/
private void queueRelatedProgrammes(Dbc dbc) {
//NOTE: refactor this as per: https://hee-tis.atlassian.net/browse/TIS21-6228
//As a Designated body name will no longer be equal to a Local Office name, and the programme
//owner is a Local Office name, the 'findByOwner()' below will become invalid.
//This may require
// (1) sync LocalOffice into sync db as well as reference.
// (2) ensure abbr field is included (its missing from the Reference LocalOffice collection)
// (3) join dbc.abbr <-> LocalOffice.abbreviation and use LocalOffice.name <-> Programme.owner
Set<Programme> programmes =
programmeSyncService.findByOwner(dbc.getData().get(DBC_NAME));

for (Programme programme : programmes) {
log.debug("DBC {} affects programme {}, "
+ "and will require related programme memberships to have RO data amended.",
dbc.getData().get(DBC_NAME), programme.getTisId());
// Default each message to LOAD.
programme.setOperation(Operation.LOAD);
String deduplicationId = fifoMessagingService
.getUniqueDeduplicationId(Programme.ENTITY_NAME, programme.getTisId());
fifoMessagingService.sendMessageToFifoQueue(programmeQueueUrl, programme, deduplicationId);
String abbr = dbc.getData().get(DBC_ABBR);
Optional<LocalOffice> localOfficeOptional = localOfficeSyncService.findByAbbreviation(abbr);

if (localOfficeOptional.isEmpty()) {
log.info("Local office {} not found, requesting data.", abbr);
localOfficeSyncService.requestByAbbr(abbr);

} else {

Set<Programme> programmes =
programmeSyncService.findByOwner(
localOfficeOptional.get().getData().get(LOCAL_OFFICE_NAME));

for (Programme programme : programmes) {
log.debug("DBC / LocalOffice {} affects programme {}, "
+ "and will require related programme memberships to have RO data amended.",
dbc.getData().get(DBC_ABBR), programme.getTisId());
// Default each message to LOAD.
programme.setOperation(Operation.LOAD);
String deduplicationId = fifoMessagingService
.getUniqueDeduplicationId(Programme.ENTITY_NAME, programme.getTisId());
fifoMessagingService.sendMessageToFifoQueue(programmeQueueUrl, programme, deduplicationId);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,11 @@
import org.springframework.data.mongodb.core.mapping.event.AfterSaveEvent;
import org.springframework.data.mongodb.core.mapping.event.BeforeDeleteEvent;
import org.springframework.stereotype.Component;
import uk.nhs.hee.tis.trainee.sync.model.Dbc;
import uk.nhs.hee.tis.trainee.sync.model.LocalOffice;
import uk.nhs.hee.tis.trainee.sync.model.Operation;
import uk.nhs.hee.tis.trainee.sync.model.Programme;
import uk.nhs.hee.tis.trainee.sync.service.DbcSyncService;
import uk.nhs.hee.tis.trainee.sync.service.FifoMessagingService;
import uk.nhs.hee.tis.trainee.sync.service.LocalOfficeSyncService;
import uk.nhs.hee.tis.trainee.sync.service.ProgrammeSyncService;
Expand All @@ -47,10 +49,12 @@
public class LocalOfficeEventListener extends AbstractMongoEventListener<LocalOffice> {

static final String LOCAL_OFFICE_NAME = "name";
static final String LOCAL_OFFICE_ABBREVIATION = "abbreviation";

private final LocalOfficeSyncService localOfficeSyncService;

private final ProgrammeSyncService programmeSyncService;
private final DbcSyncService dbcSyncService;

private final FifoMessagingService fifoMessagingService;

Expand All @@ -59,12 +63,13 @@ public class LocalOfficeEventListener extends AbstractMongoEventListener<LocalOf
private final Cache cache;

LocalOfficeEventListener(LocalOfficeSyncService localOfficeSyncService,
ProgrammeSyncService programmeService,
ProgrammeSyncService programmeService, DbcSyncService dbcSyncService,
FifoMessagingService fifoMessagingService,
@Value("${application.aws.sqs.programme}") String programmeQueueUrl,
CacheManager cacheManager) {
this.localOfficeSyncService = localOfficeSyncService;
this.programmeSyncService = programmeService;
this.dbcSyncService = dbcSyncService;
this.fifoMessagingService = fifoMessagingService;
this.programmeQueueUrl = programmeQueueUrl;
cache = cacheManager.getCache(LocalOffice.ENTITY_NAME);
Expand Down Expand Up @@ -111,25 +116,36 @@ public void onAfterDelete(AfterDeleteEvent<LocalOffice> event) {
}

/**
* Queue the programmes related to the given LocalOffice.
* Queue the programmes related to the given LocalOffice, if the related DBC is available,
* otherwise request the related DBC.
*
* @param localOffice The LocalOffice to get related programmes for.
*/
private void queueRelatedProgrammes(LocalOffice localOffice) {
//If the LO abbreviation changes then that could mean it links to a different DBC
//so then the RO could change. This seems quite unlikely but needs to be handled.
Set<Programme> programmes =
programmeSyncService.findByOwner(localOffice.getData().get(LOCAL_OFFICE_NAME));

for (Programme programme : programmes) {
log.debug("LocalOffice {} affects programme {}, "
+ "and may require related programme memberships to have RO data amended.",
localOffice.getData().get(LOCAL_OFFICE_NAME), programme.getTisId());
// Default each message to LOAD.
programme.setOperation(Operation.LOAD);
String deduplicationId = fifoMessagingService
.getUniqueDeduplicationId(Programme.ENTITY_NAME, programme.getTisId());
fifoMessagingService.sendMessageToFifoQueue(programmeQueueUrl, programme, deduplicationId);
String abbr = localOffice.getData().get(LOCAL_OFFICE_ABBREVIATION);
Optional<Dbc> dbcOptional = dbcSyncService.findByAbbr(abbr);

if (dbcOptional.isEmpty()) {
log.info("DBC {} not found, requesting data.", abbr);
dbcSyncService.requestByAbbr(abbr);

} else {

Set<Programme> programmes =
programmeSyncService.findByOwner(localOffice.getData().get(LOCAL_OFFICE_NAME));

for (Programme programme : programmes) {
log.debug("LocalOffice {} affects programme {}, "
+ "and may require related programme memberships to have RO data amended.",
localOffice.getData().get(LOCAL_OFFICE_NAME), programme.getTisId());
// Default each message to LOAD.
programme.setOperation(Operation.LOAD);
String deduplicationId = fifoMessagingService
.getUniqueDeduplicationId(Programme.ENTITY_NAME, programme.getTisId());
fifoMessagingService.sendMessageToFifoQueue(programmeQueueUrl, programme, deduplicationId);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ private void syncOrRequestMissingData(UserDesignatedBody userDesignatedBody,
if (optionalDbc.isEmpty()) {
log.info("User designated body {} {} but Dbc not found, requesting data.",
designatedBodyCodeValue, eventContext);
dbcSyncService.request(designatedBodyCodeValue);
dbcSyncService.requestByDbc(designatedBodyCodeValue);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,15 @@ public interface DbcRepository extends MongoRepository<Dbc, String> {
@Query("{'data.dbc' : ?0}")
Optional<Dbc> findByDbc(String dbc);

/**
* Find a DBC with the given abbreviation.
*
* @param abbr The designated body abbreviation to filter by.
* @return The found DBC, or nothing if not found.
*/
@Query("{'data.abbr' : ?0}")
Optional<Dbc> findByAbbr(String abbr);

@CachePut(key = "#entity.tisId")
@Override
<T extends Dbc> T save(T entity);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,23 +99,46 @@ public Optional<Dbc> findByDbc(String dbc) {
return repository.findByDbc(dbc);
}

public Optional<Dbc> findByAbbr(String abbr) {
return repository.findByAbbr(abbr);
}

/**
* Make a request to retrieve a specific Dbc.
*
* @param dbc The designated body code of the Dbc to be retrieved.
*/
public void request(String dbc) {
if (!requestCacheService.isItemInCache(Dbc.ENTITY_NAME, dbc)) {
log.info("Sending request for DBC [{}]", dbc);
public void requestByDbc(String dbc) {
request("dbc", dbc);
}

/**
* Make a request to retrieve a specific Dbc.
*
* @param abbr The designated body abbreviation of the Dbc to be retrieved.
*/
public void requestByAbbr(String abbr) {
request("abbr", abbr);
}

/**
* Make a request to retrieve a specific Dbc.
*
* @param key The field to filter the Dbc records by.
* @param value The field value of the Dbc to be retrieved.
*/
private void request(String key, String value) {
if (!requestCacheService.isItemInCache(Dbc.ENTITY_NAME, value)) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'value' can be either a dbc or an abbr. These should never overlap (share the same value), so there should never be key collisions - but if desired we could either prefix them with the type of key (to ensure uniqueness) or have two separate caches.

log.info("Sending request for DBC [{}]", value);

try {
requestCacheService.addItemToCache(Dbc.ENTITY_NAME, dbc,
dataRequestService.sendRequest("reference", Dbc.ENTITY_NAME, Map.of("dbc", dbc)));
requestCacheService.addItemToCache(Dbc.ENTITY_NAME, value,
dataRequestService.sendRequest("reference", Dbc.ENTITY_NAME, Map.of(key, value)));
} catch (JsonProcessingException e) {
log.error("Error while trying to retrieve a DBC", e);
}
} else {
log.debug("Already requested DBC [{}].", dbc);
log.debug("Already requested DBC [{}].", value);
}
}

Expand Down Expand Up @@ -143,8 +166,8 @@ public void resyncProgrammesIfUserIsResponsibleOfficer(String userName) {
* Resync the programmes related to a single user designated body, if the user has a Responsible
* Officer role.
*
* @param userName The username to filter user designated bodies by.
* @param designatedBodyCode The designated body code to filter user deisngated bodies by.
* @param userName The username to filter user designated bodies by.
* @param designatedBodyCode The designated body code to filter user deisngated bodies by.
*/
public void resyncProgrammesForSingleDbcIfUserIsResponsibleOfficer(String userName,
String designatedBodyCode) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,20 +85,21 @@ public Optional<LocalOffice> findByAbbreviation(String abbr) {
/**
* Make a request to retrieve a specific LocalOffice.
*
* @param id The id of the LocalOffice to be retrieved.
* @param abbreviation The abbreviation of the LocalOffice to be retrieved.
*/
public void request(String id) {
if (!requestCacheService.isItemInCache(LocalOffice.ENTITY_NAME, id)) {
log.info("Sending request for LocalOffice [{}]", id);
public void requestByAbbr(String abbreviation) {
if (!requestCacheService.isItemInCache(LocalOffice.ENTITY_NAME, abbreviation)) {
log.info("Sending request for LocalOffice [{}]", abbreviation);

try {
requestCacheService.addItemToCache(LocalOffice.ENTITY_NAME, id,
dataRequestService.sendRequest("reference", LocalOffice.ENTITY_NAME, Map.of("id", id)));
requestCacheService.addItemToCache(LocalOffice.ENTITY_NAME, abbreviation,
dataRequestService.sendRequest("reference", LocalOffice.ENTITY_NAME,
Map.of("abbreviation", abbreviation)));
} catch (JsonProcessingException e) {
log.error("Error while trying to retrieve a LocalOffice", e);
}
} else {
log.debug("Already requested LocalOffice [{}].", id);
log.debug("Already requested LocalOffice [{}].", abbreviation);
}
}
}
Loading
Loading