Skip to content

Commit

Permalink
allow care-gaps method to be overriden (#450)
Browse files Browse the repository at this point in the history
* allow care-gaps method to be overriden

* expanded care-gaps tests

* more parameter validation

* fixing exceptions

* method for error handling

* fix method name
  • Loading branch information
Capt-Mac committed Apr 16, 2024
1 parent 691da2a commit 92d1977
Show file tree
Hide file tree
Showing 4 changed files with 198 additions and 48 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
target
test-output
bin/
htmlReport/

.classpath
.project
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.rest.server.exceptions.NotImplementedOperationException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
import java.util.ArrayList;
Expand Down Expand Up @@ -71,7 +72,7 @@
public class R4CareGapsService {

private static final Logger ourLog = LoggerFactory.getLogger(R4CareGapsService.class);
public static final Map<String, CodeableConceptSettings> CARE_GAPS_CODES = ImmutableMap.of(
private static final Map<String, CodeableConceptSettings> CARE_GAPS_CODES = ImmutableMap.of(
"http:https://loinc.org/96315-7",
new CodeableConceptSettings().add("http:https://loinc.org", "96315-7", "Gaps in care report"),
"http:https://terminology.hl7.org/CodeSystem/v3-ActCode/CAREGAP",
Expand All @@ -88,7 +89,7 @@ public class R4CareGapsService {

private String serverBase;

private final Map<String, Resource> configuredResources = new HashMap<>();
protected final Map<String, Resource> configuredResources = new HashMap<>();

public R4CareGapsService(
CareGapsProperties careGapsProperties,
Expand Down Expand Up @@ -139,13 +140,14 @@ public Parameters getCareGapsReport(
if (!Strings.isNullOrEmpty(subject)) {
patients = getPatientListFromSubject(subject);
} else {
throw new NotImplementedOperationException(
Msg.code(2275) + "Only the subject parameter has been implemented.");
}

if (statuses.isEmpty()) {
throw new RuntimeException("CareGap 'statuses' parameter is empty");
throw new NotImplementedOperationException("Only the subject parameter has been implemented.");
}
throwNotImplementIfPresent(practitioner, "practitioner");
throwNotImplementIfPresent(organization, "organization");
listThrowNotImplementIfPresent(measureIdentifiers, "measureIdentifier");
listThrowNotImplementIfPresent(programs, "program");
listThrowNotImplementIfPresent(topic, "topic");
listThrowIllegalArgumentIfEmpty(statuses, "status");

checkValidStatusCode(statuses);

Expand All @@ -165,7 +167,25 @@ public Parameters getCareGapsReport(
return result;
}

public void validateConfiguration() {
protected void throwNotImplementIfPresent(Object value, String parameterName) {
if (value != null) {
throw new NotImplementedOperationException(parameterName + " parameter not implemented");
}
}

protected void listThrowNotImplementIfPresent(List<String> value, String parameterName) {
if (value != null && !value.isEmpty()) {
throw new NotImplementedOperationException(parameterName + " parameter not implemented");
}
}

protected void listThrowIllegalArgumentIfEmpty(List<String> value, String parameterName) {
if (value == null || value.isEmpty()) {
throw new IllegalArgumentException(parameterName + " parameter requires a value.");
}
}

protected void validateConfiguration() {
checkNotNull(careGapsProperties, "Setting care-gaps properties are required for the $care-gaps operation.");
checkArgument(
!Strings.isNullOrEmpty(careGapsProperties.getCareGapsReporter()),
Expand Down Expand Up @@ -195,21 +215,22 @@ public void validateConfiguration() {
careGapsProperties.getCareGapsCompositionSectionAuthor()));
}

List<Patient> getPatientListFromSubject(String subject) {
protected List<Patient> getPatientListFromSubject(String subject) {
if (subject.startsWith("Patient/")) {
return Collections.singletonList(validatePatientExists(subject));
} else if (subject.startsWith("Group/")) {
return getPatientListFromGroup(subject);
}

ourLog.info("Subject member was not a Patient or a Group, so skipping. \n{}", subject);
ourLog.warn("Subject member was not a Patient or a Group, so skipping. \n{}", subject);
return Collections.emptyList();
}

List<Patient> getPatientListFromGroup(String subjectGroupId) {
protected List<Patient> getPatientListFromGroup(String subjectGroupId) {
List<Patient> patientList = new ArrayList<>();
Group group = repository.read(Group.class, newId(subjectGroupId));
if (group == null) {
Group group;
try {
group = repository.read(Group.class, newId(subjectGroupId));
} catch (ResourceNotFoundException e) {
throw new IllegalArgumentException(Msg.code(2276) + "Could not find Group: " + subjectGroupId);
}

Expand All @@ -228,16 +249,18 @@ List<Patient> getPatientListFromGroup(String subjectGroupId) {
return patientList;
}

Patient validatePatientExists(String patientRef) {
Patient patient = repository.read(Patient.class, new IdType(patientRef));
if (patient == null) {
protected Patient validatePatientExists(String patientRef) {
Patient patient;
try {
patient = repository.read(Patient.class, new IdType(patientRef));
} catch (ResourceNotFoundException e) {
throw new IllegalArgumentException(Msg.code(2277) + "Could not find Patient: " + patientRef);
}

return patient;
}

List<Measure> getMeasures(
protected List<Measure> getMeasures(
List<String> measureIds, List<String> measureIdentifiers, List<CanonicalType> measureCanonicals) {
boolean hasMeasureIds = measureIds != null && !measureIds.isEmpty();
boolean hasMeasureIdentifiers = measureIdentifiers != null && !measureIdentifiers.isEmpty();
Expand All @@ -249,15 +272,15 @@ List<Measure> getMeasures(
List<Measure> measureList = new ArrayList<>();

if (hasMeasureIds) {
for (int i = 0; i < measureIds.size(); i++) {
Measure measureById = resolveById(new IdType("Measure", measureIds.get(i)));
for (String measureId : measureIds) {
Measure measureById = resolveById(new IdType("Measure", measureId));
measureList.add(measureById);
}
}

if (hasMeasureUrls) {
for (int i = 0; i < measureCanonicals.size(); i++) {
Measure measureByUrl = resolveByUrl(measureCanonicals.get(i));
for (CanonicalType measureCanonical : measureCanonicals) {
Measure measureByUrl = resolveByUrl(measureCanonical);
measureList.add(measureByUrl);
}
}
Expand Down Expand Up @@ -285,16 +308,16 @@ protected Measure resolveById(IdType id) {
return this.repository.read(Measure.class, id);
}

private <T extends Resource> T addConfiguredResource(Class<T> resourceClass, String id, String key) {
T resource = null;
protected <T extends Resource> T addConfiguredResource(Class<T> resourceClass, String id, String key) {
T resource;
// read resource from repository
resource = repository.read(resourceClass, new IdType(id));
// add resource to configured resources
configuredResources.put(key, resource);
return resource;
}

private List<Measure> ensureMeasures(List<Measure> measures) {
protected List<Measure> ensureMeasures(List<Measure> measures) {
measures.forEach(measure -> {
if (!measure.hasScoring()) {
ourLog.info("Measure does not specify a scoring so skipping: {}.", measure.getId());
Expand All @@ -308,7 +331,7 @@ private List<Measure> ensureMeasures(List<Measure> measures) {
return measures;
}

private Parameters.ParametersParameterComponent patientReports(
protected Parameters.ParametersParameterComponent patientReports(
String periodStart,
String periodEnd,
Patient patient,
Expand All @@ -330,7 +353,7 @@ private Parameters.ParametersParameterComponent patientReports(
.setResource(addBundleEntries(serverBase, composition, detectedIssues, reports, evalPlusSDE));
}

private List<MeasureReport> getReports(
protected List<MeasureReport> getReports(
String periodStart,
String periodEnd,
Patient patient,
Expand Down Expand Up @@ -386,7 +409,7 @@ private List<MeasureReport> getReports(
return reports;
}

private void initializeReport(MeasureReport measureReport) {
protected void initializeReport(MeasureReport measureReport) {
if (Strings.isNullOrEmpty(measureReport.getId())) {
IIdType id = Ids.newId(MeasureReport.class, UUID.randomUUID().toString());
measureReport.setId(id);
Expand All @@ -403,15 +426,15 @@ private void initializeReport(MeasureReport measureReport) {
}
}

private Parameters.ParametersParameterComponent initializePatientParameter(Patient patient) {
protected Parameters.ParametersParameterComponent initializePatientParameter(Patient patient) {
Parameters.ParametersParameterComponent patientParameter = Resources.newBackboneElement(
Parameters.ParametersParameterComponent.class)
.setName("return");
patientParameter.setId("subject-" + Ids.simplePart(patient));
return patientParameter;
}

private Bundle addBundleEntries(
protected Bundle addBundleEntries(
String serverBase,
Composition composition,
List<DetectedIssue> detectedIssues,
Expand All @@ -426,7 +449,7 @@ private Bundle addBundleEntries(
return reportBundle;
}

private CareGapsStatusCode getGapStatus(Measure measure, MeasureReport measureReport) {
protected CareGapsStatusCode getGapStatus(Measure measure, MeasureReport measureReport) {
Pair<String, Boolean> inNumerator = new MutablePair<>("numerator", false);
Pair<String, Boolean> inDenominator = new MutablePair<>("denominator", false);
measureReport.getGroup().forEach(group -> group.getPopulation().forEach(population -> {
Expand Down Expand Up @@ -458,11 +481,11 @@ private CareGapsStatusCode getGapStatus(Measure measure, MeasureReport measureRe
return CareGapsStatusCode.CLOSED_GAP;
}

private Bundle.BundleEntryComponent getBundleEntry(String serverBase, Resource resource) {
protected Bundle.BundleEntryComponent getBundleEntry(String serverBase, Resource resource) {
return new Bundle.BundleEntryComponent().setResource(resource).setFullUrl(getFullUrl(serverBase, resource));
}

private Composition.SectionComponent getSection(
protected Composition.SectionComponent getSection(
Measure measure, MeasureReport measureReport, DetectedIssue detectedIssue, CareGapsStatusCode gapStatus) {
String narrative = String.format(
HTML_DIV_PARAGRAPH_CONTENT,
Expand All @@ -477,14 +500,14 @@ private Composition.SectionComponent getSection(
.build();
}

private Bundle getBundle() {
protected Bundle getBundle() {
return new BundleBuilder<>(Bundle.class)
.withProfile(CARE_GAPS_BUNDLE_PROFILE)
.withType(Bundle.BundleType.DOCUMENT.toString())
.build();
}

private Composition getComposition(Patient patient) {
protected Composition getComposition(Patient patient) {
return new CompositionBuilder<>(Composition.class)
.withProfile(CARE_GAPS_COMPOSITION_PROFILE)
.withType(CARE_GAPS_CODES.get("http:https://loinc.org/96315-7"))
Expand All @@ -498,7 +521,7 @@ private Composition getComposition(Patient patient) {
.build();
}

private DetectedIssue getDetectedIssue(
protected DetectedIssue getDetectedIssue(
Patient patient, MeasureReport measureReport, CareGapsStatusCode careGapStatusCode) {
return new DetectedIssueBuilder<>(DetectedIssue.class)
.withProfile(CARE_GAPS_DETECTED_ISSUE_PROFILE)
Expand Down Expand Up @@ -564,28 +587,23 @@ protected void populateSDEResources(MeasureReport measureReport, Map<String, Res
}
}

private Parameters initializeResult() {
protected Parameters initializeResult() {
return newResource(Parameters.class, "care-gaps-report-" + UUID.randomUUID());
}

public static String getFullUrl(String serverAddress, IBaseResource resource) {
protected static String getFullUrl(String serverAddress, IBaseResource resource) {
checkArgument(
resource.getIdElement().hasIdPart(),
"Cannot generate a fullUrl because the resource does not have an id.");
return getFullUrl(serverAddress, resource.fhirType(), Ids.simplePart(resource));
}

public static String getFullUrl(String serverAddress, String fhirType, String elementId) {
protected static String getFullUrl(String serverAddress, String fhirType, String elementId) {
return String.format("%s%s/%s", serverAddress + (serverAddress.endsWith("/") ? "" : "/"), fhirType, elementId);
}

public CareGapsProperties getCareGapsProperties() {
return careGapsProperties;
}

public void checkValidStatusCode(List<String> statuses) {
for (int x = 0; x < statuses.size(); x++) {
var status = statuses.get(x);
protected void checkValidStatusCode(List<String> statuses) {
for (String status : statuses) {
if (!status.equals(CareGapsStatusCode.CLOSED_GAP.toString())
&& !status.equals(CareGapsStatusCode.OPEN_GAP.toString())
&& !status.equals(CareGapsStatusCode.NOT_APPLICABLE.toString())) {
Expand Down
Loading

0 comments on commit 92d1977

Please sign in to comment.