-
Notifications
You must be signed in to change notification settings - Fork 157
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
#3061 - Fix NPE when Measure refers to non-existent library
I applied a fix before the holiday that corrected a category of NPE errors related to execution against a measure or library resources that don't exist. It turns out that wasn't the core of the issue 3061. This goes back and addresses when a valid measure reference is used, but that Measure refers to a Library resource that does not exist. I also added some handling that allows resolution of Library resources by reference in addition to by canonical URL in the registry and also updated the error handling around retrieving the primary library reference from the Measure resource. Signed-off-by: Corey Sanders <corey.thecolonel@gmail.com>
- Loading branch information
1 parent
6915377
commit 0fde33d
Showing
15 changed files
with
461 additions
and
106 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
26 changes: 26 additions & 0 deletions
26
cql/fhir-quality-measure/src/main/java/com/ibm/fhir/ecqm/r4/MeasureHelper.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
/* | ||
* (C) Copyright IBM Corp. 2022 | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
package com.ibm.fhir.ecqm.r4; | ||
|
||
import com.ibm.fhir.exception.FHIROperationException; | ||
import com.ibm.fhir.model.resource.Measure; | ||
|
||
/** | ||
* Utility methods for working with Measure resources | ||
*/ | ||
public class MeasureHelper { | ||
public static String getPrimaryLibraryId(Measure measure) throws FHIROperationException { | ||
String primaryLibraryId = null; | ||
if( measure.getLibrary() != null && measure.getLibrary().size() == 1 ) { | ||
primaryLibraryId = measure.getLibrary().get(0).getValue(); | ||
} else { | ||
// See https://hl7.org/fhir/us/cqfmeasures/2021May/StructureDefinition-computable-measure-cqfm.html | ||
throw new FHIROperationException("Measures utilizing CQL SHALL reference one and only one CQL library (and that referenced library MUST be the primary library for the measure)"); | ||
} | ||
|
||
return primaryLibraryId; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
109 changes: 109 additions & 0 deletions
109
...peration/fhir-operation-cqf/src/main/java/com/ibm/fhir/operation/cqf/OperationHelper.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
/* | ||
* (C) Copyright IBM Corp. 2022 | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
package com.ibm.fhir.operation.cqf; | ||
|
||
import java.util.List; | ||
import java.util.Objects; | ||
import java.util.stream.Collectors; | ||
|
||
import org.opencds.cqf.cql.engine.execution.InMemoryLibraryLoader; | ||
import org.opencds.cqf.cql.engine.execution.LibraryLoader; | ||
|
||
import com.ibm.fhir.cql.helpers.LibraryHelper; | ||
import com.ibm.fhir.cql.translator.CqlTranslationProvider; | ||
import com.ibm.fhir.cql.translator.FHIRLibraryLibrarySourceProvider; | ||
import com.ibm.fhir.cql.translator.impl.InJVMCqlTranslationProvider; | ||
import com.ibm.fhir.exception.FHIROperationException; | ||
import com.ibm.fhir.model.resource.Library; | ||
import com.ibm.fhir.model.resource.Measure; | ||
import com.ibm.fhir.model.resource.Resource; | ||
import com.ibm.fhir.model.type.code.ResourceType; | ||
import com.ibm.fhir.persistence.SingleResourceResult; | ||
import com.ibm.fhir.registry.FHIRRegistry; | ||
import com.ibm.fhir.server.spi.operation.FHIRResourceHelpers; | ||
|
||
public class OperationHelper { | ||
/** | ||
* Create a library loader that will server up the CQL library content of the | ||
* provided list of FHIR Library resources. | ||
* | ||
* @param libraries | ||
* FHIR library resources | ||
* @return LibraryLoader that will serve the CQL Libraries for the provided FHIR resources | ||
*/ | ||
public static LibraryLoader createLibraryLoader(List<Library> libraries) { | ||
List<org.cqframework.cql.elm.execution.Library> result = loadCqlLibraries(libraries); | ||
return new InMemoryLibraryLoader(result); | ||
} | ||
|
||
/** | ||
* Load the CQL Library content for each of the provided FHIR Library resources with | ||
* translation as needed for Libraries with CQL attachments and no corresponding | ||
* ELM attachment. | ||
* | ||
* @param libraries | ||
* FHIR Libraries | ||
* @return CQL Libraries | ||
*/ | ||
public static List<org.cqframework.cql.elm.execution.Library> loadCqlLibraries(List<Library> libraries) { | ||
FHIRLibraryLibrarySourceProvider sourceProvider = new FHIRLibraryLibrarySourceProvider(libraries); | ||
CqlTranslationProvider translator = new InJVMCqlTranslationProvider(sourceProvider); | ||
|
||
List<org.cqframework.cql.elm.execution.Library> result = | ||
libraries.stream().flatMap(fl -> LibraryHelper.loadLibrary(translator, fl).stream()).filter(Objects::nonNull).collect(Collectors.toList()); | ||
return result; | ||
} | ||
|
||
public static Measure loadMeasureByReference(FHIRResourceHelpers resourceHelper, String reference) throws FHIROperationException { | ||
return loadResourceByReference(resourceHelper, ResourceType.MEASURE, Measure.class, reference); | ||
} | ||
|
||
|
||
public static Measure loadMeasureById(FHIRResourceHelpers resourceHelper, String reference) throws FHIROperationException { | ||
return loadResourceById(resourceHelper, ResourceType.MEASURE, reference); | ||
} | ||
|
||
public static Library loadLibraryByReference(FHIRResourceHelpers resourceHelper, String reference) throws FHIROperationException { | ||
return loadResourceByReference(resourceHelper, ResourceType.LIBRARY, Library.class, reference); | ||
} | ||
|
||
|
||
public static Library loadLibraryById(FHIRResourceHelpers resourceHelper, String reference) throws FHIROperationException { | ||
return loadResourceById(resourceHelper, ResourceType.LIBRARY, reference); | ||
} | ||
|
||
@SuppressWarnings("unchecked") | ||
public static <T extends Resource> T loadResourceByReference(FHIRResourceHelpers resourceHelper, ResourceType resourceType, Class<T> resourceClass, String reference) throws FHIROperationException { | ||
T resource; | ||
int pos = reference.indexOf('/'); | ||
if( pos == -1 || reference.startsWith(resourceType.getValue() + "/") ) { | ||
String resourceId = reference; | ||
if( pos > -1 ) { | ||
resourceId = reference.substring(pos + 1); | ||
} | ||
resource = (T) loadResourceById(resourceHelper, resourceType, resourceId); | ||
} else { | ||
resource = FHIRRegistry.getInstance().getResource(reference, resourceClass); | ||
if( resource == null ) { | ||
throw new FHIROperationException(String.format("Failed to resolve %s resource \"%s\"", resourceType.getValue(), reference)); | ||
} | ||
} | ||
|
||
return resource; | ||
} | ||
|
||
@SuppressWarnings("unchecked") | ||
public static <T extends Resource> T loadResourceById(FHIRResourceHelpers resourceHelper, ResourceType resourceType, String reference) throws FHIROperationException { | ||
T resource; | ||
try { | ||
SingleResourceResult<?> readResult = resourceHelper.doRead(resourceType.getValue(), reference, true, false, null); | ||
resource = (T) readResult.getResource(); | ||
} catch (Exception ex) { | ||
throw new FHIROperationException(String.format("Failed to resolve %s resource \"%s\"", resourceType.getValue(), reference), ex); | ||
} | ||
return resource; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.