Skip to content

Commit

Permalink
Merge branch 'develop' into MAT-5524
Browse files Browse the repository at this point in the history
  • Loading branch information
ethankaplan authored Apr 25, 2023
2 parents a84b3e0 + 5d20953 commit f5f3a0b
Show file tree
Hide file tree
Showing 21 changed files with 341 additions and 480 deletions.
5 changes: 0 additions & 5 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,6 @@
<artifactId>madie-rest-commons</artifactId>
<version>0.0.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>gov.cms.madie</groupId>
<artifactId>madie-server-commons</artifactId>
<version>0.0.1</version>
</dependency>
<dependency>
<groupId>com.okta.spring</groupId>
<artifactId>okta-spring-boot-starter</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package gov.cms.madie.madiefhirservice.exceptions;

import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;

@ResponseStatus(value = HttpStatus.NOT_FOUND)
@Slf4j
public class CqlLibraryNotFoundException extends RuntimeException {

private static final String NOT_FOUND_BY_FIND_DATA =
"Cannot find a CQL Library with name: %s, version: %s";

public CqlLibraryNotFoundException(String name, String version) {
super(String.format(NOT_FOUND_BY_FIND_DATA, name, version));
log.error(getMessage());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package gov.cms.madie.madiefhirservice.exceptions;

import gov.cms.madie.models.library.CqlLibrary;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;

@ResponseStatus(value = HttpStatus.NOT_FOUND)
@Slf4j
public class MissingCqlException extends RuntimeException {
private static final String NONE_FOUND = "Cannot find CQL for library name: %s, version: %s";

public MissingCqlException(CqlLibrary library) {
super(String.format(NONE_FOUND, library.getCqlLibraryName(), library.getVersion()));
log.warn(getMessage());
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -68,20 +68,19 @@ public HapiOperationOutcome validateBundle(HttpEntity<String> request) {

OperationOutcome requiredProfilesOutcome =
validationService.validateBundleResourcesProfiles(bundle);
OperationOutcome uniqueIdsOutcome =
validationService.validateBundleResourcesIdUniqueness(bundle);
OperationOutcome validIdsOutcome = validationService.validateBundleResourcesIdValid(bundle);

ValidationResult result = validator.validateWithResult(bundle);
try {
final OperationOutcome combinedOutcome =
validationService.combineOutcomes(
requiredProfilesOutcome,
uniqueIdsOutcome,
validIdsOutcome,
(OperationOutcome) result.toOperationOutcome());
String outcomeString = parser.encodeResourceToString(combinedOutcome);
return HapiOperationOutcome.builder()
.code(
requiredProfilesOutcome.hasIssue() || uniqueIdsOutcome.hasIssue()
requiredProfilesOutcome.hasIssue() || validIdsOutcome.hasIssue()
? HttpStatus.BAD_REQUEST.value()
: HttpStatus.OK.value())
.successful(validationService.isSuccessful(combinedOutcome))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package gov.cms.madie.madiefhirservice.services;

import gov.cms.madie.madiefhirservice.exceptions.CqlLibraryNotFoundException;
import gov.cms.madie.models.library.CqlLibrary;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;

import java.net.URI;

@Service
@Slf4j
@RequiredArgsConstructor
public class CqlLibraryService {

private final RestTemplate restTemplate;

@Value("${madie.library.service.baseUrl}")
private String madieLibraryService;

@Value("${madie.library.service.versioned.uri}")
private String librariesVersionedUri;

public CqlLibrary getLibrary(String name, String version, String accessToken) {
URI uri = buildMadieLibraryServiceUri(name, version);
log.debug("Getting Madie library: {} ", uri);

HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", accessToken);

ResponseEntity<CqlLibrary> responseEntity =
restTemplate.exchange(uri, HttpMethod.GET, new HttpEntity<>(headers), CqlLibrary.class);

if (responseEntity.getStatusCode().is2xxSuccessful()) {
if (responseEntity.hasBody()) {
log.debug("Retrieved a valid cqlPayload");
return responseEntity.getBody();
} else {
log.error("Cannot find Cql payload in the response");
return null;
}
} else if (responseEntity.getStatusCode().equals(HttpStatus.NOT_FOUND)) {
throw new CqlLibraryNotFoundException(name, version);
} else if (responseEntity.getStatusCode().equals(HttpStatus.CONFLICT)) {
log.error(
"Multiple libraries found with name: {}, version: {}, but only one was expected",
name,
version);
}
return null;
}

private URI buildMadieLibraryServiceUri(String name, String version) {
return UriComponentsBuilder.fromHttpUrl(madieLibraryService + librariesVersionedUri)
.queryParam("name", name)
.queryParam("version", version)
.build()
.encode()
.toUri();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,89 +2,38 @@

import gov.cms.madie.madiefhirservice.cql.LibraryCqlVisitor;
import gov.cms.madie.madiefhirservice.cql.LibraryCqlVisitorFactory;
import gov.cms.madie.madiefhirservice.exceptions.DuplicateLibraryException;
import gov.cms.madie.madiefhirservice.exceptions.HapiLibraryNotFoundException;
import gov.cms.madie.madiefhirservice.exceptions.LibraryAttachmentNotFoundException;
import gov.cms.madie.madiefhirservice.hapi.HapiFhirServer;
import gov.cms.madie.madiefhirservice.exceptions.MissingCqlException;
import gov.cms.madie.madiefhirservice.utils.BundleUtil;
import gov.cms.madie.models.library.CqlLibrary;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.hl7.fhir.r4.model.Attachment;
import org.hl7.fhir.r4.model.Bundle;
import org.hl7.fhir.r4.model.Library;
import org.hl7.fhir.r4.model.Narrative;
import org.hl7.fhir.r4.model.Narrative.NarrativeStatus;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Map;
import java.util.Optional;

@Service
@Slf4j
@RequiredArgsConstructor
public class LibraryService {
private final HapiFhirServer hapiFhirServer;

private final CqlLibraryService cqlLibraryService;
private final LibraryTranslatorService libraryTranslatorService;
private final LibraryCqlVisitorFactory libCqlVisitorFactory;
private final HumanReadableService humanReadableService;

public String getLibraryCql(String name, String version) {

Bundle bundle = hapiFhirServer.fetchLibraryBundleByNameAndVersion(name, version);
if (bundle.hasEntry()) {
return processBundle(name, version, bundle);
} else {
throw new HapiLibraryNotFoundException(name, version);
}
}

public CqlLibrary getLibraryResourceAsCqlLibrary(String name, String version) {
Bundle bundle = hapiFhirServer.fetchLibraryBundleByNameAndVersion(name, version);

if (bundle.hasEntry()) {
Optional<Library> optional =
hapiFhirServer.findLibraryResourceInBundle(bundle, Library.class);
return optional
.map(libraryTranslatorService::convertToCqlLibrary)
.orElseThrow(() -> new HapiLibraryNotFoundException(name, version));
} else {
throw new HapiLibraryNotFoundException(name, version);
}
}

public boolean isLibraryResourcePresent(String name, String version) {

Bundle bundle = hapiFhirServer.fetchLibraryBundleByNameAndVersion(name, version);
if (!bundle.hasEntry()) {
return false;
}

return hapiFhirServer.findLibraryResourceInBundle(bundle, Library.class).isPresent();
}

private String processBundle(String name, String version, Bundle bundle) {

Optional<Library> optional = hapiFhirServer.findLibraryResourceInBundle(bundle, Library.class);
if (optional.isPresent()) {
return getCqlFromHapiLibrary(optional.get());
} else {
throw new HapiLibraryNotFoundException(name, version);
}
}

private String getCqlFromHapiLibrary(Library library) {

List<Attachment> attachments = library.getContent();

if (CollectionUtils.isEmpty(attachments)) {
throw new LibraryAttachmentNotFoundException(library);
public String getLibraryCql(String name, String version, final String accessToken) {
CqlLibrary library = cqlLibraryService.getLibrary(name, version, accessToken);
if (StringUtils.isBlank(library.getCql())) {
throw new MissingCqlException(library);
}
Attachment cql = findCqlAttachment(library);
return new String(cql.getData());
return cqlLibraryService.getLibrary(name, version, accessToken).getCql();
}

private Attachment findCqlAttachment(Library library) {
Expand All @@ -94,45 +43,36 @@ private Attachment findCqlAttachment(Library library) {
.orElseThrow(() -> new LibraryAttachmentNotFoundException(library, "text/cql"));
}

public Library createLibraryResourceForCqlLibrary(CqlLibrary cqlLibrary) {
boolean isLibraryPresent =
isLibraryResourcePresent(
cqlLibrary.getCqlLibraryName(), cqlLibrary.getVersion().toString());

if (isLibraryPresent) {
throw new DuplicateLibraryException(
cqlLibrary.getCqlLibraryName(), cqlLibrary.getVersion().toString());
}

public Library cqlLibraryToFhirLibrary(CqlLibrary cqlLibrary, final String bundleType) {
Library library = libraryTranslatorService.convertToFhirLibrary(cqlLibrary, null);
library.setText(createLibraryNarrativeText(library));
hapiFhirServer.createResource(library);
if (BundleUtil.MEASURE_BUNDLE_TYPE_EXPORT.equals(bundleType)) {
library.setText(createLibraryNarrativeText(library));
}
return library;
}

public void getIncludedLibraries(String cql, Map<String, Library> libraryMap) {
public void getIncludedLibraries(
String cql,
Map<String, Library> libraryMap,
final String bundleType,
final String accessToken) {
if (StringUtils.isBlank(cql) || libraryMap == null) {
log.error("Invalid method arguments provided to getIncludedLibraries");
throw new IllegalArgumentException("Please provide valid arguments.");
}

LibraryCqlVisitor visitor = libCqlVisitorFactory.visit(cql);
for (Pair<String, String> libraryNameValuePair : visitor.getIncludedLibraries()) {
Optional<Library> optionalLibrary =
hapiFhirServer.fetchHapiLibrary(
libraryNameValuePair.getLeft(), libraryNameValuePair.getRight());
if (optionalLibrary.isPresent()) {
Library library = optionalLibrary.get();
String key = library.getName() + library.getVersion();
if (!libraryMap.containsKey(key)) {
libraryMap.put(key, library);
}
Attachment attachment = findCqlAttachment(library);
getIncludedLibraries(new String(attachment.getData()), libraryMap);
} else {
throw new HapiLibraryNotFoundException(
libraryNameValuePair.getLeft(), libraryNameValuePair.getRight());
CqlLibrary cqlLibrary =
cqlLibraryService.getLibrary(
libraryNameValuePair.getLeft(), libraryNameValuePair.getRight(), accessToken);
Library library = cqlLibraryToFhirLibrary(cqlLibrary, bundleType);
String key = library.getName() + library.getVersion();
if (!libraryMap.containsKey(key)) {
libraryMap.put(key, library);
}
Attachment attachment = findCqlAttachment(library);
getIncludedLibraries(new String(attachment.getData()), libraryMap, bundleType, accessToken);
}
}

Expand Down
Loading

0 comments on commit f5f3a0b

Please sign in to comment.