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

MAT-6206: Adding ability to export TestCases as type 'Collection' #165

Closed
Closed
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
Original file line number Diff line number Diff line change
@@ -1,33 +1,26 @@
package gov.cms.madie.madiefhirservice.resources;

import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.api.MethodOutcome;
import gov.cms.madie.madiefhirservice.services.ExportService;
import gov.cms.madie.madiefhirservice.services.MeasureBundleService;
import gov.cms.madie.madiefhirservice.utils.BundleUtil;
import gov.cms.madie.madiefhirservice.utils.ExportFileNamesUtil;
import gov.cms.madie.models.measure.Measure;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;

import lombok.extern.slf4j.Slf4j;
import org.hl7.fhir.r4.model.Bundle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;

@Slf4j
import ca.uhn.fhir.context.FhirContext;
import gov.cms.madie.madiefhirservice.services.ExportService;
import gov.cms.madie.madiefhirservice.services.MeasureBundleService;
import gov.cms.madie.madiefhirservice.utils.ExportFileNamesUtil;
import gov.cms.madie.models.measure.Measure;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;

@Controller
@RequestMapping(path = "/fhir/measures")
@Tag(name = "Measure-Controller", description = "Measure resources HAPI FHIR API")
Expand All @@ -47,7 +40,7 @@ public ResponseEntity<String> getMeasureBundle(
@RequestBody @Validated(Measure.ValidationSequence.class) Measure measure,
@RequestHeader(value = HttpHeaders.ACCEPT, required = false) String accept,
@RequestHeader("Authorization") String accessToken,
@RequestParam(required = false, defaultValue = "calculation", name = "bundleType")
@RequestParam(required = false, defaultValue = "CALCULATION", name = "bundleType")
Copy link
Contributor

Choose a reason for hiding this comment

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

Not a big deal, this doesn't affect functionality, we can add tech debt. we have enum that maintains this https://github.com/MeasureAuthoringTool/madie-fhir-service/blob/develop/src/main/java/gov/cms/madie/madiefhirservice/utils/BundleUtil.java

String bundleType) {

Bundle bundle =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,6 @@ public ResponseEntity<byte[]> getTestCaseExportBundle(
if (testCaseId == null || testCaseId.isEmpty()) {
throw new ResourceNotFoundException("test cases", "measure", measure.getId());
}
//MAT-6204 Here we're modifying the bundle based on export choice,
// but we don't want to modify it permanently
testCaseBundleService.setExportBundleType(exportDTO, measure);

List<TestCase> testCases =
Optional.ofNullable(measure.getTestCases())
Expand All @@ -62,7 +59,8 @@ public ResponseEntity<byte[]> getTestCaseExportBundle(
.filter(tc -> testCaseId.stream().anyMatch(id -> id.equals(tc.getId())))
.collect(Collectors.toList());
Map<String, Bundle> exportableTestCaseBundle =
testCaseBundleService.getTestCaseExportBundle(measure, testCases);
testCaseBundleService.getTestCaseExportBundle(
measure, testCases, exportDTO.getBundleType());
if (testCases.size() != exportableTestCaseBundle.size()) {
// remove the test cases that couldn't be parsed
testCases =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import gov.cms.madie.madiefhirservice.utils.BundleUtil;
import gov.cms.madie.madiefhirservice.utils.FhirResourceHelpers;
import gov.cms.madie.madiefhirservice.utils.ResourceUtils;

import gov.cms.madie.models.library.CqlLibrary;
import gov.cms.madie.models.measure.Measure;
import gov.cms.mat.cql.CqlFormatter;
Expand Down Expand Up @@ -50,7 +51,7 @@ public Bundle createMeasureBundle(

// Bundle entry for Measure resource
Bundle.BundleEntryComponent measureEntryComponent =
FhirResourceHelpers.getBundleEntryComponent(measure, "Transaction");
FhirResourceHelpers.getBundleEntryComponent(measure, Bundle.BundleType.TRANSACTION);
Bundle bundle =
new Bundle().setType(Bundle.BundleType.TRANSACTION).addEntry(measureEntryComponent);
// Bundle entries for all the library resources of a MADiE Measure
Expand Down Expand Up @@ -91,13 +92,15 @@ public List<Bundle.BundleEntryComponent> createBundleComponentsForLibrariesOfMad
Measure madieMeasure, final String bundleType, final String accessToken) {
Library library = getMeasureLibraryResourceForMadieMeasure(madieMeasure);
Bundle.BundleEntryComponent mainLibraryBundleComponent =
FhirResourceHelpers.getBundleEntryComponent(library, "Transaction");
FhirResourceHelpers.getBundleEntryComponent(library, Bundle.BundleType.TRANSACTION);
Map<String, Library> includedLibraryMap = new HashMap<>();
libraryService.getIncludedLibraries(
madieMeasure.getCql(), includedLibraryMap, bundleType, accessToken);
List<Bundle.BundleEntryComponent> libraryBundleComponents =
includedLibraryMap.values().stream()
.map((lib) -> FhirResourceHelpers.getBundleEntryComponent(lib, "Transaction"))
.map(
(lib) ->
FhirResourceHelpers.getBundleEntryComponent(lib, Bundle.BundleType.TRANSACTION))
.collect(Collectors.toList());
// add main library first in the list
libraryBundleComponents.add(0, mainLibraryBundleComponent);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@
import org.apache.commons.lang3.time.DateFormatUtils;
import org.hl7.fhir.r4.model.BooleanType;
import org.hl7.fhir.r4.model.Bundle;

import org.hl7.fhir.r4.model.Bundle.HTTPVerb;
import org.hl7.fhir.r4.model.Extension;
import org.hl7.fhir.r4.model.MarkdownType;
import org.hl7.fhir.r4.model.MeasureReport;
Expand All @@ -49,7 +47,6 @@
import gov.cms.madie.madiefhirservice.utils.ExportFileNamesUtil;
import gov.cms.madie.madiefhirservice.utils.FhirResourceHelpers;
import gov.cms.madie.models.common.BundleType;
import gov.cms.madie.models.dto.ExportDTO;
import gov.cms.madie.models.measure.Measure;
import gov.cms.madie.models.measure.TestCase;
import gov.cms.madie.packaging.utils.PackagingUtility;
Expand All @@ -64,7 +61,8 @@ public class TestCaseBundleService {

private final FhirContext fhirContext;

public Map<String, Bundle> getTestCaseExportBundle(Measure measure, List<TestCase> testCases) {
public Map<String, Bundle> getTestCaseExportBundle(
Measure measure, List<TestCase> testCases, BundleType bundleType) {
if (measure == null || testCases == null || testCases.isEmpty()) {
throw new InternalServerException("Unable to find Measure and/or test case");
}
Expand All @@ -85,6 +83,11 @@ public Map<String, Bundle> getTestCaseExportBundle(Measure measure, List<TestCas
throw new DataFormatException("TestCase Json is empty");
}
bundle = parser.parseResource(Bundle.class, testCase.getJson());
if (bundleType != null) {
bundle.setType(
org.hl7.fhir.r4.model.Bundle.BundleType.valueOf(bundleType.toString().toUpperCase()));
bundle = FhirResourceHelpers.setTestCaseBundleEntryComponent(bundle);
}
} catch (DataFormatException | ClassCastException ex) {
log.error(
"Unable to parse test case bundle resource for test case [{}] from Measure [{}]",
Expand All @@ -95,9 +98,9 @@ public Map<String, Bundle> getTestCaseExportBundle(Measure measure, List<TestCas

String fileName = ExportFileNamesUtil.getTestCaseExportFileName(measure, testCase);
var measureReport = buildMeasureReport(testCase, measure, bundle);

var bundleEntryComponent =
FhirResourceHelpers.getBundleEntryComponent(
measureReport, String.valueOf(bundle.getType()));
FhirResourceHelpers.getBundleEntryComponent(measureReport, bundle.getType());
bundle.getEntry().add(bundleEntryComponent);
testCaseBundle.put(fileName, bundle);
}
Expand All @@ -110,41 +113,6 @@ public Map<String, Bundle> getTestCaseExportBundle(Measure measure, List<TestCas
return testCaseBundle;
}

public void updateEntry(TestCase testCase, BundleType bundleType) {

// Convert Test case JSON to a BUndle
IParser parser =
fhirContext
.newJsonParser()
.setParserErrorHandler(new StrictErrorHandler())
.setPrettyPrint(true);
Bundle bundle = parser.parseResource(Bundle.class, testCase.getJson());

// modify the bundle
org.hl7.fhir.r4.model.Bundle.BundleType fhirBundleType =
org.hl7.fhir.r4.model.Bundle.BundleType.valueOf(bundleType.toString().toUpperCase());
bundle.setType(fhirBundleType);
bundle.setEntry(
bundle.getEntry().stream()
.map(
entry -> {
if (bundleType == BundleType.TRANSACTION) {


FhirResourceHelpers.setResourceEntry(entry.getResource(), entry);
return entry;
} else if (bundleType == BundleType.COLLECTION) {
entry.setRequest(null);
}
return entry;
})
.collect(Collectors.toList()));
// bundle to json
String json = parser.encodeResourceToString(bundle);

testCase.setJson(json);
}

private MeasureReport buildMeasureReport(
TestCase testCase, Measure measure, Bundle testCaseBundle) {
MeasureReport measureReport = new MeasureReport();
Expand Down Expand Up @@ -319,26 +287,6 @@ private String generateReadMe(List<TestCase> testCases) {
return readMe;
}

public void setExportBundleType(ExportDTO exportDTO, Measure measure) {
if (exportDTO.getBundleType() != null) {
BundleType bundleType = BundleType.valueOf(exportDTO.getBundleType().name());
switch (bundleType) {
case COLLECTION:
log.debug("You're exporting a Collection");
// update bundle type for each entry MAT 6405
break;
case TRANSACTION:
log.debug("You're exporting a Transaction");
// update bundle type and add entry.request for each entry
if (measure.getTestCases() != null) {
measure.getTestCases().stream().forEach(testCase -> updateEntry(testCase, bundleType));
}
break;
default:
}
}
}

/**
* Combines the zip from Packaging Utility and a generated ReadMe file for the testcases
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
import org.hl7.fhir.r4.model.Bundle;
import org.hl7.fhir.r4.model.Bundle.BundleType;
import org.hl7.fhir.r4.model.CodeableConcept;
import org.hl7.fhir.r4.model.Coding;
import org.hl7.fhir.r4.model.Period;
Expand All @@ -11,6 +12,7 @@

import java.util.ArrayList;
import java.util.Date;
import java.util.stream.Collectors;

@Component
public class FhirResourceHelpers {
Expand All @@ -21,26 +23,55 @@ public void setMadieUrl(String url) {
FhirResourceHelpers.madieUrl = url;
}

public static Bundle setTestCaseBundleEntryComponent(Bundle bundle) {

// modify the bundle
org.hl7.fhir.r4.model.Bundle.BundleType fhirBundleType =
org.hl7.fhir.r4.model.Bundle.BundleType.valueOf(bundle.getType().toString().toUpperCase());
bundle.setType(fhirBundleType);
bundle.setEntry(
bundle.getEntry().stream()
.map(
entry -> {
if (org.hl7.fhir.r4.model.Bundle.BundleType.valueOf(
bundle.getType().toString().toUpperCase())
== BundleType.TRANSACTION) {
FhirResourceHelpers.setResourceEntry(entry.getResource(), entry);
return entry;
} else if (org.hl7.fhir.r4.model.Bundle.BundleType.valueOf(
bundle.getType().toString().toUpperCase())
== BundleType.COLLECTION) {
entry.setRequest(null);
}
return entry;
})
.collect(Collectors.toList()));
// bundle to json

return bundle;
}

public static Bundle.BundleEntryComponent getBundleEntryComponent(
Resource resource, String bundleType) {
Resource resource, Bundle.BundleType bundleType) {
Bundle.BundleEntryComponent entryComponent =
new Bundle.BundleEntryComponent()
.setFullUrl(buildResourceFullUrl(resource.fhirType(), resource.getIdPart()))
.setResource(resource);
// for the transaction bundles, add request object to the entry
if ("Transaction".equalsIgnoreCase(bundleType)) {
if (bundleType == Bundle.BundleType.TRANSACTION) {
setResourceEntry(resource, entryComponent);
}
return entryComponent;
}

public static void setResourceEntry(Resource resource, Bundle.BundleEntryComponent entryComponent) {
Bundle.BundleEntryRequestComponent requestComponent =
new Bundle.BundleEntryRequestComponent()
.setMethod(Bundle.HTTPVerb.POST)
.setUrl(resource.getResourceType() + "/" + resource.getIdPart());
entryComponent.setRequest(requestComponent);
}
public static void setResourceEntry(
Resource resource, Bundle.BundleEntryComponent entryComponent) {
Bundle.BundleEntryRequestComponent requestComponent =
new Bundle.BundleEntryRequestComponent()
.setMethod(Bundle.HTTPVerb.POST)
.setUrl(resource.getResourceType() + "/" + resource.getIdPart());
entryComponent.setRequest(requestComponent);
}

public static Period getPeriodFromDates(Date startDate, Date endDate) {
return new Period()
Expand Down
Loading
Loading