Skip to content

Commit

Permalink
issue #3192 - fhirVersion-aware CapabilityStatement
Browse files Browse the repository at this point in the history
Signed-off-by: Lee Surprenant <[email protected]>
  • Loading branch information
lmsurpre committed May 12, 2022
1 parent 798e74a commit b91f34a
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
Expand All @@ -41,6 +42,7 @@
import javax.ws.rs.Consumes;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
Expand Down Expand Up @@ -121,6 +123,23 @@ public class Capabilities extends FHIRResource {
.map(rt -> ResourceType.Value.from(rt.getSimpleName()))
.collect(Collectors.toList());

private static final Set<ResourceType.Value> R4B_ONLY_RESOURCES = new HashSet<>();
{
R4B_ONLY_RESOURCES.add(ResourceType.Value.ADMINISTRABLE_PRODUCT_DEFINITION);
R4B_ONLY_RESOURCES.add(ResourceType.Value.CITATION);
R4B_ONLY_RESOURCES.add(ResourceType.Value.CLINICAL_USE_DEFINITION);
R4B_ONLY_RESOURCES.add(ResourceType.Value.EVIDENCE_REPORT);
R4B_ONLY_RESOURCES.add(ResourceType.Value.INGREDIENT);
R4B_ONLY_RESOURCES.add(ResourceType.Value.MANUFACTURED_ITEM_DEFINITION);
R4B_ONLY_RESOURCES.add(ResourceType.Value.MEDICINAL_PRODUCT_DEFINITION);
R4B_ONLY_RESOURCES.add(ResourceType.Value.NUTRITION_PRODUCT);
R4B_ONLY_RESOURCES.add(ResourceType.Value.PACKAGED_PRODUCT_DEFINITION);
R4B_ONLY_RESOURCES.add(ResourceType.Value.REGULATED_AUTHORIZATION);
R4B_ONLY_RESOURCES.add(ResourceType.Value.SUBSCRIPTION_STATUS);
R4B_ONLY_RESOURCES.add(ResourceType.Value.SUBSCRIPTION_TOPIC);
R4B_ONLY_RESOURCES.add(ResourceType.Value.SUBSTANCE_DEFINITION);
}

// Error Messages
private static final String ERROR_MSG = "Caught exception while processing 'metadata' request.";
private static final String ERROR_CONSTRUCTING = "An error occurred while constructing the Conformance statement.";
Expand All @@ -137,7 +156,7 @@ public Capabilities() throws Exception {

@GET
@Path("metadata")
public Response capabilities(@QueryParam("mode") @DefaultValue("full") String mode) {
public Response capabilities(@QueryParam("mode") @DefaultValue("full") String mode, @HeaderParam("accept") String accept) {
log.entering(this.getClass().getName(), "capabilities()");
try {
Date startTime = new Date();
Expand All @@ -147,13 +166,17 @@ public Response capabilities(@QueryParam("mode") @DefaultValue("full") String mo
throw new IllegalArgumentException("Invalid mode parameter: must be one of [full, normative, terminology]");
}

FHIRVersion fhirVersion = getFhirVersion(accept);

// Defaults to 60 minutes (or what's in the fhirConfig)
int cacheTimeout = FHIRConfigHelper.getIntProperty(PROPERTY_CAPABILITY_STATEMENT_CACHE, 60);
Configuration configuration = Configuration.of(Duration.of(cacheTimeout, ChronoUnit.MINUTES));

Map<String, Resource> cacheAsMap = CacheManager.getCacheAsMap(CAPABILITY_STATEMENT_CACHE_NAME, configuration);
CacheManager.reportCacheStats(log, CAPABILITY_STATEMENT_CACHE_NAME);
Resource capabilityStatement = cacheAsMap.computeIfAbsent(mode, k -> computeCapabilityStatement(mode));

String cacheKey = mode + "-" + fhirVersion.getValue();
Resource capabilityStatement = cacheAsMap.computeIfAbsent(cacheKey, k -> computeCapabilityStatement(mode, fhirVersion));

RestAuditLogger.logMetadata(httpServletRequest, startTime, new Date(), Response.Status.OK);

Expand All @@ -179,19 +202,38 @@ public Response capabilities(@QueryParam("mode") @DefaultValue("full") String mo
}
}

/**
* Which FHIRVersion to use for the generated CapabilityStatement
*
* @param acceptHeaderValue
* @return 4.3.0 if the client is asking for it, otherwise 4.0.1
*/
private FHIRVersion getFhirVersion(String acceptHeaderValue) {
if (acceptHeaderValue != null && !acceptHeaderValue.isEmpty()) {
for (String headerValueElement : acceptHeaderValue.split(",")) {
String requestedVersion = MediaType.valueOf(headerValueElement).getParameters().get(FHIRMediaType.FHIR_VERSION_PARAMETER);
if ("4.3".equals(requestedVersion) || "4.3.0".equals(requestedVersion)) {
// TODO: remove _CIBUILD after generating from the published 4.3.0 artifacts
return FHIRVersion.VERSION_4_3_0_CIBUILD;
}
}
}
return FHIRVersion.VERSION_4_0_1;
}

private boolean isValidMode(String mode) {
return "full".equals(mode) || "normative".equals(mode) || "terminology".equals(mode);
}

private Resource computeCapabilityStatement(String mode) {
private Resource computeCapabilityStatement(String mode, FHIRVersion fhirVersion) {
try {
switch (mode) {
case "terminology":
return buildTerminologyCapabilities();
case "full":
case "normative":
default:
return buildCapabilityStatement();
return buildCapabilityStatement(fhirVersion);
}
} catch (Exception e) {
throw new RuntimeException(e);
Expand Down Expand Up @@ -289,7 +331,7 @@ private List<TerminologyCapabilities.CodeSystem> buildCodeSystem() {
*
* @throws Exception
*/
private CapabilityStatement buildCapabilityStatement() throws Exception {
private CapabilityStatement buildCapabilityStatement(FHIRVersion fhirVersion) throws Exception {
// Retrieve the "resources" config property group.
PropertyGroup rsrcsGroup = FHIRConfigHelper.getPropertyGroup(FHIRConfiguration.PROPERTY_RESOURCES);

Expand Down Expand Up @@ -353,13 +395,17 @@ private CapabilityStatement buildCapabilityStatement() throws Exception {
}

com.ibm.fhir.model.type.Boolean isUpdateCreate = com.ibm.fhir.model.type.Boolean.of(isUpdateCreateEnabled());
<<<<<<< HEAD

FHIRVersion fhirVersion = FHIRVersion.VERSION_4_0_1;

=======

>>>>>>> 2b4dfe67da (issue #3192 - fhirVersion-aware CapabilityStatement)
// Build the list of supported resources.
List<Rest.Resource> resources = new ArrayList<>();

List<ResourceType.Value> resourceTypes = getSupportedResourceTypes(rsrcsGroup);
List<ResourceType.Value> resourceTypes = getSupportedResourceTypes(rsrcsGroup, fhirVersion);

for (ResourceType.Value resourceType : resourceTypes) {
String resourceTypeName = resourceType.value();
Expand Down Expand Up @@ -661,11 +707,22 @@ private List<com.ibm.fhir.model.type.String> convertStringList(List<String> stri
* @return a list of resource types to support
* @throws Exception
*/
private List<ResourceType.Value> getSupportedResourceTypes(PropertyGroup rsrcsGroup) throws Exception {
private List<ResourceType.Value> getSupportedResourceTypes(PropertyGroup rsrcsGroup, FHIRVersion fhirVersion) throws Exception {
final List<ResourceType.Value> resourceTypes = new ArrayList<>();

if (rsrcsGroup == null) {
return ALL_RESOURCE_TYPES;
resourceTypes.addAll(ALL_RESOURCE_TYPES);
} else {
if (rsrcsGroup.getBooleanProperty(FHIRConfiguration.PROPERTY_FIELD_RESOURCES_OPEN, true)) {
resourceTypes.addAll(ALL_RESOURCE_TYPES);
} else {
resourceTypes.addAll(FHIRConfigHelper.getSupportedResourceTypes().stream()
.map(ResourceType.Value::from)
.collect(Collectors.toList()));
}
}

<<<<<<< HEAD
List<ResourceType.Value> resourceTypes = new ArrayList<>();
if (rsrcsGroup.getBooleanProperty(FHIRConfiguration.PROPERTY_FIELD_RESOURCES_OPEN, true)) {
resourceTypes = ALL_RESOURCE_TYPES;
Expand All @@ -678,6 +735,10 @@ private List<ResourceType.Value> getSupportedResourceTypes(PropertyGroup rsrcsGr
.map(ResourceType.Value::from)
.collect(Collectors.toList());
>>>>>>> c9cadcb75b (issues #3184 and #3186 - update Capabilities)
=======
if (fhirVersion.getValueAsEnum() == FHIRVersion.Value.VERSION_4_0_1) {
resourceTypes.removeAll(R4B_ONLY_RESOURCES);
>>>>>>> 2b4dfe67da (issue #3192 - fhirVersion-aware CapabilityStatement)
}
return resourceTypes;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@
import com.ibm.fhir.server.resources.Capabilities;

public class CapabilitiesTest {
private static final boolean DEBUG = false;

SearchHelper searchHelper = new SearchHelper();

@BeforeClass
Expand All @@ -49,22 +47,38 @@ void testBuildCapabilityStatement_resources_omitted() throws Exception {
FHIRRequestContext.get().setOriginalRequestUri("http://example.com/metadata");
CapabilitiesChild c = new CapabilitiesChild(searchHelper);

Response capabilities = c.capabilities("full");
Response capabilities = c.capabilities("full", null);
CapabilityStatement capabilityStatement = capabilities.readEntity(CapabilityStatement.class);

assertEquals(capabilityStatement.getRest().size(), 1, "Number of REST Elements");
CapabilityStatement.Rest restDefinition = capabilityStatement.getRest().get(0);

assertRestDefinition(restDefinition, 4, 141, 9, 1, 1, 9, 1, 1);
assertRestDefinition(restDefinition, 4, 128, 9, 1, 1, 9, 1, 1);
}

@Test
void testBuildCapabilityStatement_resources_empty() throws Exception {
void testBuildCapabilityStatement_resources_empty_r4() throws Exception {
FHIRRequestContext.get().setTenantId("empty");
FHIRRequestContext.get().setOriginalRequestUri("http://example.com/metadata");
CapabilitiesChild c = new CapabilitiesChild(searchHelper);

Response capabilities = c.capabilities("full");
Response capabilities = c.capabilities("full", "application/fhir+json;fhirVersion=4.0");
CapabilityStatement capabilityStatement = capabilities.readEntity(CapabilityStatement.class);

assertEquals(capabilityStatement.getRest().size(), 1, "Number of REST Elements");
CapabilityStatement.Rest restDefinition = capabilityStatement.getRest().get(0);

// batch and transaction
assertRestDefinition(restDefinition, 2, 128, 0, 0, 0, 0, 0, 0);
}

@Test
void testBuildCapabilityStatement_resources_empty_r4b() throws Exception {
FHIRRequestContext.get().setTenantId("empty");
FHIRRequestContext.get().setOriginalRequestUri("http://example.com/metadata");
CapabilitiesChild c = new CapabilitiesChild();

Response capabilities = c.capabilities("full", "application/fhir+json;fhirVersion=4.3");
CapabilityStatement capabilityStatement = capabilities.readEntity(CapabilityStatement.class);

assertEquals(capabilityStatement.getRest().size(), 1, "Number of REST Elements");
Expand All @@ -79,7 +93,7 @@ void testBuildCapabilityStatement_resources_filtered() throws Exception {
FHIRRequestContext.get().setOriginalRequestUri("http://example.com/metadata");
CapabilitiesChild c = new CapabilitiesChild(searchHelper);

Response capabilities = c.capabilities("full");
Response capabilities = c.capabilities("full", "");
CapabilityStatement capabilityStatement = capabilities.readEntity(CapabilityStatement.class);

assertEquals(capabilityStatement.getRest().size(), 1, "Number of REST Elements");
Expand Down Expand Up @@ -130,9 +144,9 @@ public CapabilitiesChild(SearchHelper searchHelper) throws Exception {
}

@Override
public Response capabilities(String mode) {
public Response capabilities(String mode, String acceptHeaderValue) {
httpServletRequest = new MockHttpServletRequest();
return super.capabilities(mode);
return super.capabilities(mode, acceptHeaderValue);
}

@Override
Expand Down

0 comments on commit b91f34a

Please sign in to comment.