From 1ca24482d10f5cb35b6b9a557826bb0182e6bf36 Mon Sep 17 00:00:00 2001 From: Luke deGruchy Date: Tue, 15 Oct 2024 09:28:25 -0400 Subject: [PATCH 1/2] Add interfaces to duplicate CR 3.13.0 branch. Spotless --- .../R4MeasureEvaluatorMultiple.java | 53 ++++++ .../R4MeasureEvaluatorSingle.java | 52 ++++++ .../R4MeasureService.java | 88 ++++++++++ .../R4MultiMeasureService.java | 166 ++++++++++++++++++ .../ca/uhn/fhir/cr/config/r4/CrR4Config.java | 2 +- .../fhir/cr/r4/IMeasureServiceFactory.java | 4 +- 6 files changed, 362 insertions(+), 3 deletions(-) create mode 100644 hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/clinical_reasoning_copy/R4MeasureEvaluatorMultiple.java create mode 100644 hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/clinical_reasoning_copy/R4MeasureEvaluatorSingle.java create mode 100644 hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/clinical_reasoning_copy/R4MeasureService.java create mode 100644 hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/clinical_reasoning_copy/R4MultiMeasureService.java diff --git a/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/clinical_reasoning_copy/R4MeasureEvaluatorMultiple.java b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/clinical_reasoning_copy/R4MeasureEvaluatorMultiple.java new file mode 100644 index 00000000000..99b59347338 --- /dev/null +++ b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/clinical_reasoning_copy/R4MeasureEvaluatorMultiple.java @@ -0,0 +1,53 @@ +/*- + * #%L + * HAPI FHIR - Clinical Reasoning + * %% + * Copyright (C) 2014 - 2024 Smile CDR, Inc. + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ +package ca.uhn.fhir.cr.clinical_reasoning_copy; + +import org.hl7.fhir.r4.model.Bundle; +import org.hl7.fhir.r4.model.CanonicalType; +import org.hl7.fhir.r4.model.Endpoint; +import org.hl7.fhir.r4.model.IdType; +import org.hl7.fhir.r4.model.Measure; +import org.hl7.fhir.r4.model.Parameters; +import org.opencds.cqf.fhir.cr.measure.r4.R4MultiMeasureService; +import org.opencds.cqf.fhir.utility.monad.Either3; + +import java.util.List; + +/** + * Interface for {@link R4MultiMeasureService} and any other concrete classes that implement the same + * signature. + */ +public interface R4MeasureEvaluatorMultiple { + + Bundle evaluate( + List> measures, + String periodStart, + String periodEnd, + String reportType, + String subjectId, + Endpoint contentEndpoint, + Endpoint terminologyEndpoint, + Endpoint dataEndpoint, + Bundle additionalData, + Parameters parameters, + String productLine, + String practitioner, + String reporter); +} diff --git a/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/clinical_reasoning_copy/R4MeasureEvaluatorSingle.java b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/clinical_reasoning_copy/R4MeasureEvaluatorSingle.java new file mode 100644 index 00000000000..594ed1c4d6c --- /dev/null +++ b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/clinical_reasoning_copy/R4MeasureEvaluatorSingle.java @@ -0,0 +1,52 @@ +/*- + * #%L + * HAPI FHIR - Clinical Reasoning + * %% + * Copyright (C) 2014 - 2024 Smile CDR, Inc. + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ +package ca.uhn.fhir.cr.clinical_reasoning_copy; + +import org.hl7.fhir.r4.model.Bundle; +import org.hl7.fhir.r4.model.CanonicalType; +import org.hl7.fhir.r4.model.Endpoint; +import org.hl7.fhir.r4.model.IdType; +import org.hl7.fhir.r4.model.Measure; +import org.hl7.fhir.r4.model.MeasureReport; +import org.hl7.fhir.r4.model.Parameters; +import org.opencds.cqf.fhir.cr.measure.r4.R4MeasureService; +import org.opencds.cqf.fhir.utility.monad.Either3; + +/** + * Interface for {@link R4MeasureService} and any other concrete classes that implement the same + * signature. + */ +public interface R4MeasureEvaluatorSingle { + + MeasureReport evaluate( + Either3 measure, + String periodStart, + String periodEnd, + String reportType, + String subjectId, + String lastReceivedOn, + Endpoint contentEndpoint, + Endpoint terminologyEndpoint, + Endpoint dataEndpoint, + Bundle additionalData, + Parameters parameters, + String productLine, + String practitioner); +} diff --git a/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/clinical_reasoning_copy/R4MeasureService.java b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/clinical_reasoning_copy/R4MeasureService.java new file mode 100644 index 00000000000..50890ae9a2f --- /dev/null +++ b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/clinical_reasoning_copy/R4MeasureService.java @@ -0,0 +1,88 @@ +/*- + * #%L + * HAPI FHIR - Clinical Reasoning + * %% + * Copyright (C) 2014 - 2024 Smile CDR, Inc. + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ +package ca.uhn.fhir.cr.clinical_reasoning_copy; + +import org.apache.commons.lang3.StringUtils; +import org.hl7.fhir.r4.model.*; +import org.opencds.cqf.fhir.api.Repository; +import org.opencds.cqf.fhir.cr.measure.MeasureEvaluationOptions; +import org.opencds.cqf.fhir.cr.measure.r4.R4MeasureProcessor; +import org.opencds.cqf.fhir.cr.measure.r4.R4RepositorySubjectProvider; +import org.opencds.cqf.fhir.cr.measure.r4.utils.R4MeasureServiceUtils; +import org.opencds.cqf.fhir.utility.monad.Either3; +import org.opencds.cqf.fhir.utility.repository.Repositories; + +import java.util.Collections; + +public class R4MeasureService implements R4MeasureEvaluatorSingle { + private final Repository repository; + private final MeasureEvaluationOptions measureEvaluationOptions; + + public R4MeasureService(Repository repository, MeasureEvaluationOptions measureEvaluationOptions) { + this.repository = repository; + this.measureEvaluationOptions = measureEvaluationOptions; + } + + public MeasureReport evaluate( + Either3 measure, + String periodStart, + String periodEnd, + String reportType, + String subjectId, + String lastReceivedOn, + Endpoint contentEndpoint, + Endpoint terminologyEndpoint, + Endpoint dataEndpoint, + Bundle additionalData, + Parameters parameters, + String productLine, + String practitioner) { + + var repo = Repositories.proxy(repository, true, dataEndpoint, contentEndpoint, terminologyEndpoint); + var processor = new R4MeasureProcessor(repo, this.measureEvaluationOptions, new R4RepositorySubjectProvider()); + + R4MeasureServiceUtils r4MeasureServiceUtils = new R4MeasureServiceUtils(repository); + r4MeasureServiceUtils.ensureSupplementalDataElementSearchParameter(); + + MeasureReport measureReport = null; + + if (StringUtils.isNotBlank(practitioner)) { + if (!practitioner.contains("/")) { + practitioner = "Practitioner/".concat(practitioner); + } + subjectId = practitioner; + } + + measureReport = processor.evaluateMeasure( + measure, + periodStart, + periodEnd, + reportType, + Collections.singletonList(subjectId), + additionalData, + parameters); + + // add ProductLine after report is generated + measureReport = r4MeasureServiceUtils.addProductLineExtension(measureReport, productLine); + + // add subject reference for non-individual reportTypes + return r4MeasureServiceUtils.addSubjectReference(measureReport, practitioner, subjectId); + } +} diff --git a/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/clinical_reasoning_copy/R4MultiMeasureService.java b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/clinical_reasoning_copy/R4MultiMeasureService.java new file mode 100644 index 00000000000..247b5d7182e --- /dev/null +++ b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/clinical_reasoning_copy/R4MultiMeasureService.java @@ -0,0 +1,166 @@ +/*- + * #%L + * HAPI FHIR - Clinical Reasoning + * %% + * Copyright (C) 2014 - 2024 Smile CDR, Inc. + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ +package ca.uhn.fhir.cr.clinical_reasoning_copy; + +import com.google.common.base.Strings; +import org.apache.commons.lang3.StringUtils; +import org.hl7.fhir.instance.model.api.IIdType; +import org.hl7.fhir.r4.model.Bundle; +import org.hl7.fhir.r4.model.Bundle.BundleType; +import org.hl7.fhir.r4.model.CanonicalType; +import org.hl7.fhir.r4.model.Endpoint; +import org.hl7.fhir.r4.model.IdType; +import org.hl7.fhir.r4.model.Measure; +import org.hl7.fhir.r4.model.MeasureReport; +import org.hl7.fhir.r4.model.Parameters; +import org.hl7.fhir.r4.model.Resource; +import org.opencds.cqf.fhir.api.Repository; +import org.opencds.cqf.fhir.cr.measure.MeasureEvaluationOptions; +import org.opencds.cqf.fhir.cr.measure.common.MeasureEvalType; +import org.opencds.cqf.fhir.cr.measure.r4.R4MeasureProcessor; +import org.opencds.cqf.fhir.cr.measure.r4.R4RepositorySubjectProvider; +import org.opencds.cqf.fhir.cr.measure.r4.utils.R4MeasureServiceUtils; +import org.opencds.cqf.fhir.utility.Ids; +import org.opencds.cqf.fhir.utility.builder.BundleBuilder; +import org.opencds.cqf.fhir.utility.monad.Either3; +import org.opencds.cqf.fhir.utility.repository.Repositories; + +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +import static org.opencds.cqf.fhir.cr.measure.r4.utils.R4MeasureServiceUtils.getFullUrl; + +// Alternate MeasureService call to Process MeasureEvaluation for the selected population of subjects against n-number +// of measure resources. The output of this operation would be a bundle of MeasureReports instead of MeasureReport. + +public class R4MultiMeasureService implements R4MeasureEvaluatorMultiple { + private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(R4MultiMeasureService.class); + private final Repository repository; + private final MeasureEvaluationOptions measureEvaluationOptions; + private String serverBase; + + public R4MultiMeasureService( + Repository repository, MeasureEvaluationOptions measureEvaluationOptions, String serverBase) { + this.repository = repository; + this.measureEvaluationOptions = measureEvaluationOptions; + this.serverBase = serverBase; + } + + public Bundle evaluate( + List> measures, + String periodStart, + String periodEnd, + String reportType, + String subjectId, + Endpoint contentEndpoint, + Endpoint terminologyEndpoint, + Endpoint dataEndpoint, + Bundle additionalData, + Parameters parameters, + String productLine, + String practitioner, + String reporter) { + + var repo = Repositories.proxy(repository, true, dataEndpoint, contentEndpoint, terminologyEndpoint); + + var subjectProvider = new R4RepositorySubjectProvider(); + + var processor = new R4MeasureProcessor(repo, this.measureEvaluationOptions, subjectProvider); + + R4MeasureServiceUtils r4MeasureServiceUtils = new R4MeasureServiceUtils(repository); + r4MeasureServiceUtils.ensureSupplementalDataElementSearchParameter(); + + log.info("multi-evaluate-measure, measures to evaluate: {}", measures.size()); + + var evalType = MeasureEvalType.fromCode(reportType) + .orElse( + subjectId == null || subjectId.isEmpty() + ? MeasureEvalType.POPULATION + : MeasureEvalType.SUBJECT); + + // get subjects + var subjects = getSubjects(subjectProvider, practitioner, subjectId, evalType); + + // create bundle + Bundle bundle = new BundleBuilder<>(Bundle.class) + .withType(BundleType.SEARCHSET.toString()) + .build(); + + for (Either3 measure : measures) { + MeasureReport measureReport; + // evaluate each measure + measureReport = processor.evaluateMeasure( + measure, periodStart, periodEnd, reportType, subjects, additionalData, parameters, evalType); + + // add ProductLine after report is generated + measureReport = r4MeasureServiceUtils.addProductLineExtension(measureReport, productLine); + + // add subject reference for non-individual reportTypes + measureReport = r4MeasureServiceUtils.addSubjectReference(measureReport, practitioner, subjectId); + + // add reporter if available + if (reporter != null && !reporter.isEmpty()) { + measureReport.setReporter(r4MeasureServiceUtils.getReporter(reporter)); + } + // add id to measureReport + initializeReport(measureReport); + + // add report to bundle + bundle.addEntry(getBundleEntry(serverBase, measureReport)); + + // progress feedback + var measureUrl = measureReport.getMeasure(); + if (!measureUrl.isEmpty()) { + log.info("MeasureReport complete for Measure: {}", measureUrl); + } + } + + return bundle; + } + + protected List getSubjects( + R4RepositorySubjectProvider subjectProvider, + String practitioner, + String subjectId, + MeasureEvalType evalType) { + // check for practitioner parameter before subject + if (StringUtils.isNotBlank(practitioner)) { + if (!practitioner.contains("/")) { + practitioner = "Practitioner/".concat(practitioner); + } + subjectId = practitioner; + } + + return subjectProvider.getSubjects(repository, evalType, subjectId).collect(Collectors.toList()); + } + + protected void initializeReport(MeasureReport measureReport) { + if (Strings.isNullOrEmpty(measureReport.getId())) { + IIdType id = Ids.newId(MeasureReport.class, UUID.randomUUID().toString()); + measureReport.setId(id); + } + } + + // LUKETODO: figure out a way to reuse this between clinical-reasoning and cdr + public Bundle.BundleEntryComponent getBundleEntry(String serverBase, Resource resource) { + return new Bundle.BundleEntryComponent().setResource(resource).setFullUrl(getFullUrl(serverBase, resource)); + } +} diff --git a/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/config/r4/CrR4Config.java b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/config/r4/CrR4Config.java index 3cdc398e0c0..5b8bd194455 100644 --- a/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/config/r4/CrR4Config.java +++ b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/config/r4/CrR4Config.java @@ -21,6 +21,7 @@ package ca.uhn.fhir.cr.config.r4; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirVersionEnum; +import ca.uhn.fhir.cr.clinical_reasoning_copy.R4MeasureService; import ca.uhn.fhir.cr.common.IRepositoryFactory; import ca.uhn.fhir.cr.common.RepositoryFactoryForRepositoryInterface; import ca.uhn.fhir.cr.config.ProviderLoader; @@ -49,7 +50,6 @@ import org.opencds.cqf.fhir.cr.measure.MeasureEvaluationOptions; import org.opencds.cqf.fhir.cr.measure.r4.R4CareGapsService; import org.opencds.cqf.fhir.cr.measure.r4.R4CollectDataService; import org.opencds.cqf.fhir.cr.measure.r4.R4DataRequirementsService; -import org.opencds.cqf.fhir.cr.measure.r4.R4MeasureService; import org.opencds.cqf.fhir.cr.measure.r4.R4SubmitDataService; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.ApplicationContext; diff --git a/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/r4/IMeasureServiceFactory.java b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/r4/IMeasureServiceFactory.java index 70bc842ab1c..21e78d8ec44 100644 --- a/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/r4/IMeasureServiceFactory.java +++ b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/r4/IMeasureServiceFactory.java @@ -19,10 +19,10 @@ */ package ca.uhn.fhir.cr.r4; +import ca.uhn.fhir.cr.clinical_reasoning_copy.R4MeasureEvaluatorSingle; import ca.uhn.fhir.rest.api.server.RequestDetails; -import org.opencds.cqf.fhir.cr.measure.r4.R4MeasureService; @FunctionalInterface public interface IMeasureServiceFactory { - R4MeasureService create(RequestDetails theRequestDetails); + R4MeasureEvaluatorSingle create(RequestDetails theRequestDetails); } From e86ca9dc36ec5348e9e595023f00ec9aecee01bd Mon Sep 17 00:00:00 2001 From: Luke deGruchy Date: Wed, 23 Oct 2024 11:02:20 -0400 Subject: [PATCH 2/2] Fix compile errors. Get rid of temporary pre 3.13 code. --- .../R4MeasureEvaluatorMultiple.java | 53 ------ .../R4MeasureEvaluatorSingle.java | 52 ------ .../R4MeasureService.java | 88 ---------- .../R4MultiMeasureService.java | 166 ------------------ .../ca/uhn/fhir/cr/config/r4/CrR4Config.java | 2 +- .../fhir/cr/r4/IMeasureServiceFactory.java | 2 +- 6 files changed, 2 insertions(+), 361 deletions(-) delete mode 100644 hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/clinical_reasoning_copy/R4MeasureEvaluatorMultiple.java delete mode 100644 hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/clinical_reasoning_copy/R4MeasureEvaluatorSingle.java delete mode 100644 hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/clinical_reasoning_copy/R4MeasureService.java delete mode 100644 hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/clinical_reasoning_copy/R4MultiMeasureService.java diff --git a/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/clinical_reasoning_copy/R4MeasureEvaluatorMultiple.java b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/clinical_reasoning_copy/R4MeasureEvaluatorMultiple.java deleted file mode 100644 index 99b59347338..00000000000 --- a/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/clinical_reasoning_copy/R4MeasureEvaluatorMultiple.java +++ /dev/null @@ -1,53 +0,0 @@ -/*- - * #%L - * HAPI FHIR - Clinical Reasoning - * %% - * Copyright (C) 2014 - 2024 Smile CDR, Inc. - * %% - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * #L% - */ -package ca.uhn.fhir.cr.clinical_reasoning_copy; - -import org.hl7.fhir.r4.model.Bundle; -import org.hl7.fhir.r4.model.CanonicalType; -import org.hl7.fhir.r4.model.Endpoint; -import org.hl7.fhir.r4.model.IdType; -import org.hl7.fhir.r4.model.Measure; -import org.hl7.fhir.r4.model.Parameters; -import org.opencds.cqf.fhir.cr.measure.r4.R4MultiMeasureService; -import org.opencds.cqf.fhir.utility.monad.Either3; - -import java.util.List; - -/** - * Interface for {@link R4MultiMeasureService} and any other concrete classes that implement the same - * signature. - */ -public interface R4MeasureEvaluatorMultiple { - - Bundle evaluate( - List> measures, - String periodStart, - String periodEnd, - String reportType, - String subjectId, - Endpoint contentEndpoint, - Endpoint terminologyEndpoint, - Endpoint dataEndpoint, - Bundle additionalData, - Parameters parameters, - String productLine, - String practitioner, - String reporter); -} diff --git a/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/clinical_reasoning_copy/R4MeasureEvaluatorSingle.java b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/clinical_reasoning_copy/R4MeasureEvaluatorSingle.java deleted file mode 100644 index 594ed1c4d6c..00000000000 --- a/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/clinical_reasoning_copy/R4MeasureEvaluatorSingle.java +++ /dev/null @@ -1,52 +0,0 @@ -/*- - * #%L - * HAPI FHIR - Clinical Reasoning - * %% - * Copyright (C) 2014 - 2024 Smile CDR, Inc. - * %% - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * #L% - */ -package ca.uhn.fhir.cr.clinical_reasoning_copy; - -import org.hl7.fhir.r4.model.Bundle; -import org.hl7.fhir.r4.model.CanonicalType; -import org.hl7.fhir.r4.model.Endpoint; -import org.hl7.fhir.r4.model.IdType; -import org.hl7.fhir.r4.model.Measure; -import org.hl7.fhir.r4.model.MeasureReport; -import org.hl7.fhir.r4.model.Parameters; -import org.opencds.cqf.fhir.cr.measure.r4.R4MeasureService; -import org.opencds.cqf.fhir.utility.monad.Either3; - -/** - * Interface for {@link R4MeasureService} and any other concrete classes that implement the same - * signature. - */ -public interface R4MeasureEvaluatorSingle { - - MeasureReport evaluate( - Either3 measure, - String periodStart, - String periodEnd, - String reportType, - String subjectId, - String lastReceivedOn, - Endpoint contentEndpoint, - Endpoint terminologyEndpoint, - Endpoint dataEndpoint, - Bundle additionalData, - Parameters parameters, - String productLine, - String practitioner); -} diff --git a/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/clinical_reasoning_copy/R4MeasureService.java b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/clinical_reasoning_copy/R4MeasureService.java deleted file mode 100644 index 50890ae9a2f..00000000000 --- a/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/clinical_reasoning_copy/R4MeasureService.java +++ /dev/null @@ -1,88 +0,0 @@ -/*- - * #%L - * HAPI FHIR - Clinical Reasoning - * %% - * Copyright (C) 2014 - 2024 Smile CDR, Inc. - * %% - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * #L% - */ -package ca.uhn.fhir.cr.clinical_reasoning_copy; - -import org.apache.commons.lang3.StringUtils; -import org.hl7.fhir.r4.model.*; -import org.opencds.cqf.fhir.api.Repository; -import org.opencds.cqf.fhir.cr.measure.MeasureEvaluationOptions; -import org.opencds.cqf.fhir.cr.measure.r4.R4MeasureProcessor; -import org.opencds.cqf.fhir.cr.measure.r4.R4RepositorySubjectProvider; -import org.opencds.cqf.fhir.cr.measure.r4.utils.R4MeasureServiceUtils; -import org.opencds.cqf.fhir.utility.monad.Either3; -import org.opencds.cqf.fhir.utility.repository.Repositories; - -import java.util.Collections; - -public class R4MeasureService implements R4MeasureEvaluatorSingle { - private final Repository repository; - private final MeasureEvaluationOptions measureEvaluationOptions; - - public R4MeasureService(Repository repository, MeasureEvaluationOptions measureEvaluationOptions) { - this.repository = repository; - this.measureEvaluationOptions = measureEvaluationOptions; - } - - public MeasureReport evaluate( - Either3 measure, - String periodStart, - String periodEnd, - String reportType, - String subjectId, - String lastReceivedOn, - Endpoint contentEndpoint, - Endpoint terminologyEndpoint, - Endpoint dataEndpoint, - Bundle additionalData, - Parameters parameters, - String productLine, - String practitioner) { - - var repo = Repositories.proxy(repository, true, dataEndpoint, contentEndpoint, terminologyEndpoint); - var processor = new R4MeasureProcessor(repo, this.measureEvaluationOptions, new R4RepositorySubjectProvider()); - - R4MeasureServiceUtils r4MeasureServiceUtils = new R4MeasureServiceUtils(repository); - r4MeasureServiceUtils.ensureSupplementalDataElementSearchParameter(); - - MeasureReport measureReport = null; - - if (StringUtils.isNotBlank(practitioner)) { - if (!practitioner.contains("/")) { - practitioner = "Practitioner/".concat(practitioner); - } - subjectId = practitioner; - } - - measureReport = processor.evaluateMeasure( - measure, - periodStart, - periodEnd, - reportType, - Collections.singletonList(subjectId), - additionalData, - parameters); - - // add ProductLine after report is generated - measureReport = r4MeasureServiceUtils.addProductLineExtension(measureReport, productLine); - - // add subject reference for non-individual reportTypes - return r4MeasureServiceUtils.addSubjectReference(measureReport, practitioner, subjectId); - } -} diff --git a/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/clinical_reasoning_copy/R4MultiMeasureService.java b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/clinical_reasoning_copy/R4MultiMeasureService.java deleted file mode 100644 index 247b5d7182e..00000000000 --- a/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/clinical_reasoning_copy/R4MultiMeasureService.java +++ /dev/null @@ -1,166 +0,0 @@ -/*- - * #%L - * HAPI FHIR - Clinical Reasoning - * %% - * Copyright (C) 2014 - 2024 Smile CDR, Inc. - * %% - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * #L% - */ -package ca.uhn.fhir.cr.clinical_reasoning_copy; - -import com.google.common.base.Strings; -import org.apache.commons.lang3.StringUtils; -import org.hl7.fhir.instance.model.api.IIdType; -import org.hl7.fhir.r4.model.Bundle; -import org.hl7.fhir.r4.model.Bundle.BundleType; -import org.hl7.fhir.r4.model.CanonicalType; -import org.hl7.fhir.r4.model.Endpoint; -import org.hl7.fhir.r4.model.IdType; -import org.hl7.fhir.r4.model.Measure; -import org.hl7.fhir.r4.model.MeasureReport; -import org.hl7.fhir.r4.model.Parameters; -import org.hl7.fhir.r4.model.Resource; -import org.opencds.cqf.fhir.api.Repository; -import org.opencds.cqf.fhir.cr.measure.MeasureEvaluationOptions; -import org.opencds.cqf.fhir.cr.measure.common.MeasureEvalType; -import org.opencds.cqf.fhir.cr.measure.r4.R4MeasureProcessor; -import org.opencds.cqf.fhir.cr.measure.r4.R4RepositorySubjectProvider; -import org.opencds.cqf.fhir.cr.measure.r4.utils.R4MeasureServiceUtils; -import org.opencds.cqf.fhir.utility.Ids; -import org.opencds.cqf.fhir.utility.builder.BundleBuilder; -import org.opencds.cqf.fhir.utility.monad.Either3; -import org.opencds.cqf.fhir.utility.repository.Repositories; - -import java.util.List; -import java.util.UUID; -import java.util.stream.Collectors; - -import static org.opencds.cqf.fhir.cr.measure.r4.utils.R4MeasureServiceUtils.getFullUrl; - -// Alternate MeasureService call to Process MeasureEvaluation for the selected population of subjects against n-number -// of measure resources. The output of this operation would be a bundle of MeasureReports instead of MeasureReport. - -public class R4MultiMeasureService implements R4MeasureEvaluatorMultiple { - private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(R4MultiMeasureService.class); - private final Repository repository; - private final MeasureEvaluationOptions measureEvaluationOptions; - private String serverBase; - - public R4MultiMeasureService( - Repository repository, MeasureEvaluationOptions measureEvaluationOptions, String serverBase) { - this.repository = repository; - this.measureEvaluationOptions = measureEvaluationOptions; - this.serverBase = serverBase; - } - - public Bundle evaluate( - List> measures, - String periodStart, - String periodEnd, - String reportType, - String subjectId, - Endpoint contentEndpoint, - Endpoint terminologyEndpoint, - Endpoint dataEndpoint, - Bundle additionalData, - Parameters parameters, - String productLine, - String practitioner, - String reporter) { - - var repo = Repositories.proxy(repository, true, dataEndpoint, contentEndpoint, terminologyEndpoint); - - var subjectProvider = new R4RepositorySubjectProvider(); - - var processor = new R4MeasureProcessor(repo, this.measureEvaluationOptions, subjectProvider); - - R4MeasureServiceUtils r4MeasureServiceUtils = new R4MeasureServiceUtils(repository); - r4MeasureServiceUtils.ensureSupplementalDataElementSearchParameter(); - - log.info("multi-evaluate-measure, measures to evaluate: {}", measures.size()); - - var evalType = MeasureEvalType.fromCode(reportType) - .orElse( - subjectId == null || subjectId.isEmpty() - ? MeasureEvalType.POPULATION - : MeasureEvalType.SUBJECT); - - // get subjects - var subjects = getSubjects(subjectProvider, practitioner, subjectId, evalType); - - // create bundle - Bundle bundle = new BundleBuilder<>(Bundle.class) - .withType(BundleType.SEARCHSET.toString()) - .build(); - - for (Either3 measure : measures) { - MeasureReport measureReport; - // evaluate each measure - measureReport = processor.evaluateMeasure( - measure, periodStart, periodEnd, reportType, subjects, additionalData, parameters, evalType); - - // add ProductLine after report is generated - measureReport = r4MeasureServiceUtils.addProductLineExtension(measureReport, productLine); - - // add subject reference for non-individual reportTypes - measureReport = r4MeasureServiceUtils.addSubjectReference(measureReport, practitioner, subjectId); - - // add reporter if available - if (reporter != null && !reporter.isEmpty()) { - measureReport.setReporter(r4MeasureServiceUtils.getReporter(reporter)); - } - // add id to measureReport - initializeReport(measureReport); - - // add report to bundle - bundle.addEntry(getBundleEntry(serverBase, measureReport)); - - // progress feedback - var measureUrl = measureReport.getMeasure(); - if (!measureUrl.isEmpty()) { - log.info("MeasureReport complete for Measure: {}", measureUrl); - } - } - - return bundle; - } - - protected List getSubjects( - R4RepositorySubjectProvider subjectProvider, - String practitioner, - String subjectId, - MeasureEvalType evalType) { - // check for practitioner parameter before subject - if (StringUtils.isNotBlank(practitioner)) { - if (!practitioner.contains("/")) { - practitioner = "Practitioner/".concat(practitioner); - } - subjectId = practitioner; - } - - return subjectProvider.getSubjects(repository, evalType, subjectId).collect(Collectors.toList()); - } - - protected void initializeReport(MeasureReport measureReport) { - if (Strings.isNullOrEmpty(measureReport.getId())) { - IIdType id = Ids.newId(MeasureReport.class, UUID.randomUUID().toString()); - measureReport.setId(id); - } - } - - // LUKETODO: figure out a way to reuse this between clinical-reasoning and cdr - public Bundle.BundleEntryComponent getBundleEntry(String serverBase, Resource resource) { - return new Bundle.BundleEntryComponent().setResource(resource).setFullUrl(getFullUrl(serverBase, resource)); - } -} diff --git a/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/config/r4/CrR4Config.java b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/config/r4/CrR4Config.java index 538dc424e6a..c627ef15e39 100644 --- a/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/config/r4/CrR4Config.java +++ b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/config/r4/CrR4Config.java @@ -21,7 +21,6 @@ package ca.uhn.fhir.cr.config.r4; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirVersionEnum; -import ca.uhn.fhir.cr.clinical_reasoning_copy.R4MeasureService; import ca.uhn.fhir.cr.common.IRepositoryFactory; import ca.uhn.fhir.cr.common.RepositoryFactoryForRepositoryInterface; import ca.uhn.fhir.cr.common.StringTimePeriodHandler; @@ -50,6 +49,7 @@ import org.opencds.cqf.fhir.cr.measure.common.MeasurePeriodValidator; import org.opencds.cqf.fhir.cr.measure.r4.R4CareGapsService; import org.opencds.cqf.fhir.cr.measure.r4.R4CollectDataService; import org.opencds.cqf.fhir.cr.measure.r4.R4DataRequirementsService; +import org.opencds.cqf.fhir.cr.measure.r4.R4MeasureService; import org.opencds.cqf.fhir.cr.measure.r4.R4SubmitDataService; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; diff --git a/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/r4/IMeasureServiceFactory.java b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/r4/IMeasureServiceFactory.java index 21e78d8ec44..6e9c03f0c37 100644 --- a/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/r4/IMeasureServiceFactory.java +++ b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/r4/IMeasureServiceFactory.java @@ -19,8 +19,8 @@ */ package ca.uhn.fhir.cr.r4; -import ca.uhn.fhir.cr.clinical_reasoning_copy.R4MeasureEvaluatorSingle; import ca.uhn.fhir.rest.api.server.RequestDetails; +import org.opencds.cqf.fhir.cr.measure.r4.R4MeasureEvaluatorSingle; @FunctionalInterface public interface IMeasureServiceFactory {