Skip to content

Commit

Permalink
MAT-6916: Implement basic endpoint for triggering database update
Browse files Browse the repository at this point in the history
  • Loading branch information
mcmcphillips committed Mar 27, 2024
1 parent aad60ab commit d38cc2c
Show file tree
Hide file tree
Showing 13 changed files with 196 additions and 147 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@

@Configuration
public class WebFluxConfiguration implements WebFluxConfigurer {
@Override
public void configureHttpMessageCodecs(ServerCodecConfigurer configurer) {
configurer.defaultCodecs().maxInMemorySize(500 * 1024);
}
}
@Override
public void configureHttpMessageCodecs(ServerCodecConfigurer configurer) {
configurer.defaultCodecs().maxInMemorySize(500 * 1024);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,19 +38,19 @@ public class VsacController {

@GetMapping(path = "/valueset", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<String> getValueSet(
Principal principal,
@RequestParam String oid,
@RequestParam(required = false, name = "profile") String profile,
@RequestParam(required = false, name = "includeDraft") String includeDraft,
@RequestParam(required = false, name = "release") String release,
@RequestParam(required = false, name = "version") String version) {
Principal principal,
@RequestParam String oid,
@RequestParam(required = false, name = "profile") String profile,
@RequestParam(required = false, name = "includeDraft") String includeDraft,
@RequestParam(required = false, name = "release") String release,
@RequestParam(required = false, name = "version") String version) {
log.debug("Entering: getValueSet()");

final String username = principal.getName();
Optional<UmlsUser> umlsUser = vsacService.findByHarpId(username);
if (umlsUser.isPresent()) {
RetrieveMultipleValueSetsResponse valuesetResponse =
vsacService.getValueSet(oid, umlsUser.get(), profile, includeDraft, release, version);
vsacService.getValueSet(oid, umlsUser.get(), profile, includeDraft, release, version);

ValueSet fhirValueSet = vsacService.convertToFHIRValueSet(valuesetResponse);
log.debug("valueset id = " + fhirValueSet.getId());
Expand All @@ -67,19 +67,19 @@ protected String serializeFhirValueset(ValueSet fhirValueSet) {

@PutMapping(path = "/value-sets/searches", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<String> searchValueSets(
Principal principal, @RequestBody ValueSetsSearchCriteria searchCriteria) {
Principal principal, @RequestBody ValueSetsSearchCriteria searchCriteria) {
log.debug("VsacController::getValueSets");

final String username = principal.getName();
Optional<UmlsUser> umlsUser = vsacService.findByHarpId(username);
if (umlsUser.isPresent()) {

List<RetrieveMultipleValueSetsResponse> vsacValueSets =
vsacService.getValueSets(searchCriteria, umlsUser.get());
vsacService.getValueSets(searchCriteria, umlsUser.get());

List<ValueSet> fhirValueSets = vsacService.convertToFHIRValueSets(vsacValueSets);
String serializedValueSets =
fhirValueSets.stream().map(this::serializeFhirValueset).collect(Collectors.joining(", "));
fhirValueSets.stream().map(this::serializeFhirValueset).collect(Collectors.joining(", "));

return ResponseEntity.ok().body("[" + serializedValueSets + "]");
}
Expand All @@ -88,14 +88,14 @@ public ResponseEntity<String> searchValueSets(

@PutMapping("/qdm/value-sets/searches")
public ResponseEntity<List<QdmValueSet>> getQdmValueSets(
Principal principal, @RequestBody ValueSetsSearchCriteria searchCriteria) {
Principal principal, @RequestBody ValueSetsSearchCriteria searchCriteria) {
log.debug("VsacController::getQdmValueSets");

final String username = principal.getName();
Optional<UmlsUser> umlsUser = vsacService.findByHarpId(username);
if (umlsUser.isPresent()) {
List<QdmValueSet> qdmValueSets =
vsacService.getValueSetsInQdmFormat(searchCriteria, umlsUser.get());
vsacService.getValueSetsInQdmFormat(searchCriteria, umlsUser.get());

return ResponseEntity.ok().body(qdmValueSets);
}
Expand All @@ -104,9 +104,9 @@ public ResponseEntity<List<QdmValueSet>> getQdmValueSets(

@PutMapping(path = "/validations/codes", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<List<CqlCode>> validateCodes(
Principal principal,
@RequestBody List<CqlCode> cqlCodes,
@RequestParam(required = false, defaultValue = "FHIR") String model) {
Principal principal,
@RequestBody List<CqlCode> cqlCodes,
@RequestParam(required = false, defaultValue = "FHIR") String model) {
final String username = principal.getName();
Optional<UmlsUser> umlsUser = vsacService.findByHarpId(username);
if (umlsUser.isPresent() && umlsUser.get().getApiKey() != null) {
Expand All @@ -131,23 +131,7 @@ public ResponseEntity<String> umlsLogin(Principal principal, @RequestBody String
@GetMapping("/umls-credentials/status")
public ResponseEntity<Boolean> checkUserLogin(Principal principal) {
return vsacService.validateUmlsInformation(principal.getName())
? ResponseEntity.ok().body(Boolean.TRUE)
: new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
}

@GetMapping(path = "/update-code-systems", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<List<ManifestExpansion>> retrieveAndUpdateCodeSystems(Principal principal) {
final String username = principal.getName();
Optional<UmlsUser> umlsUser = vsacService.findByHarpId(username);

if (umlsUser.isPresent() && !StringUtils.isBlank(umlsUser.get().getApiKey())) {
return ResponseEntity.ok().body(fhirTerminologyService.retrieveAllCodeSystems(umlsUser.get()));
}
else{
log.error(
"Unable to Retrieve List of code systems, "
+ "UMLS Authentication Key Not found for user : [{}}]",
username);
throw new VsacUnauthorizedException("Please login to UMLS before proceeding"); }
? ResponseEntity.ok().body(Boolean.TRUE)
: new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@
import gov.cms.madie.terminology.dto.QdmValueSet;
import gov.cms.madie.terminology.dto.ValueSetsSearchCriteria;
import gov.cms.madie.terminology.exceptions.VsacUnauthorizedException;
import gov.cms.madie.terminology.models.CodeSystem;
import gov.cms.madie.terminology.models.UmlsUser;
import gov.cms.madie.terminology.service.FhirTerminologyService;
import gov.cms.madie.terminology.service.VsacService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

Expand Down Expand Up @@ -59,4 +61,21 @@ public ResponseEntity<List<QdmValueSet>> getValueSetsExpansions(
username);
throw new VsacUnauthorizedException("Please login to UMLS before proceeding");
}

@GetMapping(path = "/update-code-systems", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<List<CodeSystem>> retrieveAndUpdateCodeSystems(Principal principal) {
final String username = principal.getName();
Optional<UmlsUser> umlsUser = vsacService.findByHarpId(username);

if (umlsUser.isPresent() && !StringUtils.isBlank(umlsUser.get().getApiKey())) {
return ResponseEntity.ok()
.body(fhirTerminologyService.retrieveAllCodeSystems(umlsUser.get()));
} else {
log.error(
"Unable to Retrieve List of code systems, "
+ "UMLS Authentication Key Not found for user : [{}}]",
username);
throw new VsacUnauthorizedException("Please login to UMLS before proceeding");
}
}
}
12 changes: 5 additions & 7 deletions src/main/java/gov/cms/madie/terminology/models/CodeSystem.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,10 @@
@Builder(toBuilder = true)
@NoArgsConstructor
@Document

public class CodeSystem {
@Id private String id; //version ID
private String name;
private String version;
private Identifier identifier; // identifier[0] of identifier List
private Meta meta;
private Instant lastUpdated;
@Id private String versionId; // meta().versionId
private String name;
private String version;
private String value; // identifier[0].value oid of identifier List
private Instant lastUpdated; // when we got it
}

This file was deleted.

9 changes: 0 additions & 9 deletions src/main/java/gov/cms/madie/terminology/models/Meta.java

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package gov.cms.madie.terminology.repositories;

import gov.cms.madie.terminology.models.CodeSystem;
import org.springframework.data.mongodb.repository.MongoRepository;
import java.util.Optional;

public interface CodeSystemRepository extends MongoRepository<CodeSystem, String> {
Optional<CodeSystem> findByVersionId(String versionId);

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@

import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.parser.IParser;
import gov.cms.madie.models.cql.terminology.VsacCode;
import gov.cms.madie.models.mapping.CodeSystemEntry;
import gov.cms.madie.models.measure.ManifestExpansion;
import gov.cms.madie.terminology.dto.QdmValueSet;
import gov.cms.madie.terminology.dto.ValueSetsSearchCriteria;
import gov.cms.madie.terminology.models.CodeSystem;
import gov.cms.madie.terminology.models.UmlsUser;
import gov.cms.madie.terminology.repositories.CodeSystemRepository;
import gov.cms.madie.terminology.util.TerminologyServiceUtil;
import gov.cms.madie.terminology.webclient.FhirTerminologyServiceWebClient;
import lombok.RequiredArgsConstructor;
Expand All @@ -16,7 +17,9 @@
import org.hl7.fhir.r4.model.ValueSet;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.web.util.UriComponentsBuilder;

import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
Expand All @@ -28,7 +31,7 @@ public class FhirTerminologyService {
private final FhirContext fhirContext;
private final FhirTerminologyServiceWebClient fhirTerminologyServiceWebClient;
private final MappingService mappingService;

private final CodeSystemRepository codeSystemRepository;
@Cacheable("manifest-list")
public List<ManifestExpansion> getManifests(UmlsUser umlsUser) {
IParser parser = fhirContext.newJsonParser();
Expand Down Expand Up @@ -110,28 +113,72 @@ private List<QdmValueSet.Concept> getValueSetConcepts(
return List.of();
}

// call individual
public List<ManifestExpansion> retrieveCodeSystemsPage(UmlsUser umlsUser){
// one to call only, one to mutate and build
public Bundle retrieveCodeSystemsPage(UmlsUser umlsUser, Integer offset, Integer count) {
IParser parser = fhirContext.newJsonParser();
String responseString = fhirTerminologyServiceWebClient.getCodeSystemsPage(0, 100, umlsUser.getApiKey());
Bundle CodeSystemsBundle = parser.parseResource(Bundle.class, responseString);
var CodeSystemsOptions = new ArrayList<ManifestExpansion>();
CodeSystemsBundle
.getEntry()
.forEach(
entry ->
CodeSystemsOptions.add(
ManifestExpansion.builder()
.id(entry.getResource().getIdPart())
.fullUrl(entry.getFullUrl())
.build()));
return CodeSystemsOptions;
String responseString =
fhirTerminologyServiceWebClient.getCodeSystemsPage(offset, count, umlsUser.getApiKey());
return parser.parseResource(
Bundle.class, responseString);
}

public List<ManifestExpansion> retrieveAllCodeSystems(UmlsUser umlsUser) {

return retrieveCodeSystemsPage(umlsUser);
// save
private void updateOrInsertAllCodeSystems(List<CodeSystem> codeSystemList){
for (CodeSystem codeSystem : codeSystemList) {
Optional<CodeSystem> existingCodeSystemOptional = codeSystemRepository.findByVersionId(codeSystem.getVersionId());
if (existingCodeSystemOptional.isPresent()) {
// Update existing CodeSystem
CodeSystem existingCodeSystem = existingCodeSystemOptional.get();
existingCodeSystem.setName(codeSystem.getName());
existingCodeSystem.setValue(codeSystem.getValue());
existingCodeSystem.setLastUpdated(Instant.now());
codeSystemRepository.save(existingCodeSystem);
log.info("CodeSystem updated: {}", existingCodeSystem);
} else {
// Insert new CodeSystem
codeSystemRepository.save(codeSystem);
log.info("New CodeSystem inserted: {}", codeSystem);
}
}
}
private void recursiveRetrieveCodeSystems(UmlsUser umlsUser, Integer offset, Integer count, List<CodeSystem> allCodeSystems) {
log.info("requesting page offset: {} count: {}", offset, count);
Bundle codeSystemBundle = retrieveCodeSystemsPage(umlsUser, offset, count);
List<CodeSystem> codeSystemsPage = new ArrayList<>(); // build small list
codeSystemBundle.getEntry().forEach(entry -> {
var codeSystem = (org.hl7.fhir.r4.model.CodeSystem) entry.getResource();
String codeSystemValue = "";
if (!codeSystem.getIdentifier().isEmpty()) {
codeSystemValue = codeSystem.getIdentifier().get(0).getValue();
}
codeSystemsPage.add(
CodeSystem.builder()
.versionId(codeSystem.getMeta().getVersionId())
.version(codeSystem.getVersion())
.name(codeSystem.getName())
.value(codeSystemValue)
.lastUpdated(Instant.now())
.build());
});
allCodeSystems.addAll(codeSystemsPage); // update big list
var links = codeSystemBundle.getLink();
links.forEach((l) -> {
if (l.getRelation().equals("next")){
// if next, call self and continue until fail.
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(l.getUrl());
String newOffset = builder.build().getQueryParams().getFirst("_offset");
String newCount = builder.build().getQueryParams().getFirst("_count");
assert newOffset != null;
assert newCount != null;
recursiveRetrieveCodeSystems(umlsUser, Integer.parseInt(newOffset), Integer.parseInt(newCount), allCodeSystems);
}
});
}
public List<CodeSystem> retrieveAllCodeSystems(UmlsUser umlsUser) {
List<CodeSystem> allCodeSystems = new ArrayList<>();

recursiveRetrieveCodeSystems(umlsUser, 0, 50, allCodeSystems);
// Once we have all codeSystems, update DB using mongo
updateOrInsertAllCodeSystems(allCodeSystems);
return allCodeSystems;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,15 @@ public static URI buildRetrieveCodeUri(String baseUrl, String codePath) {
}

public static URI buildRetrieveCodeSystemsUri(String baseUrl, Integer offset, Integer count) {
// http://uat-cts.nlm.nih.gov/fhir/res/CodeSystem?_offset=100&_count=100
// http://uat-cts.nlm.nih.gov/fhir/res/CodeSystem?_offset=100&_count=100
return UriComponentsBuilder.fromUriString(baseUrl)
.queryParam("_offset", Integer.toString(offset))
.queryParam("_count", Integer.toString(count))
.buildAndExpand().encode().toUri();
.queryParam("_offset", Integer.toString(offset))
.queryParam("_count", Integer.toString(count))
.buildAndExpand()
.encode()
.toUri();
}

public static String buildCodePath(
String codeSystemName, String codeSystemVersion, String codeId) {
// "/CodeSystem/LOINC22/Version/2.67/Code/21112-8/Info";
Expand Down
Loading

0 comments on commit d38cc2c

Please sign in to comment.