Issue 5081 support mdm on version r5 (#5099)

* Create SubscriptionTopic before creating Subscription for MDM loader when on R5

* Remove unused properties

* MdmSubscriptionLoader changes to support R5 in MDM - added SubscriptionTopic queryCriteria (draft)

* MDM not supported for R5 - implementation

* MDM not supported for R5 - implementation

* MDM not supported for R5 - implementation fix

* MDM not supported for R5 - implementation fix

* MDM not supported for R5 - implementation fix

* MDM not supported for R5 - implementation fix

* MDM not supported for R5 - implementation fix

* MDM not supported for R5 - implementation fix

* MDM not supported for R5 - implementation fix

* MDM not supported for R5 - implementation fixes, changelog

* MDM not supported for R5 - fixes

* MDM not supported for R5 - fixes

* MDM not supported for R5 - fixes

* MDM not supported for R5 - fix

---------

Co-authored-by: juan.marchionatto <juan.marchionatto@smilecdr.com>
Co-authored-by: volodymyr <volodymyr.korzh@smilecdr.com>
This commit is contained in:
jmarchionatto 2023-11-23 12:22:05 -05:00 committed by GitHub
parent f624cf75ad
commit a1aa9c4a36
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 335 additions and 26 deletions

View File

@ -0,0 +1,4 @@
---
type: add
issue: 5081
title: "Added MDM support for FHIR R5."

View File

@ -20,6 +20,7 @@
package ca.uhn.fhir.jpa.mdm.broker;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.interceptor.api.HookParams;
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
@ -30,6 +31,7 @@ import ca.uhn.fhir.jpa.mdm.svc.MdmResourceFilteringSvc;
import ca.uhn.fhir.jpa.mdm.svc.candidate.TooManyCandidatesException;
import ca.uhn.fhir.jpa.subscription.model.ResourceModifiedJsonMessage;
import ca.uhn.fhir.jpa.subscription.model.ResourceModifiedMessage;
import ca.uhn.fhir.jpa.topic.SubscriptionTopicUtil;
import ca.uhn.fhir.mdm.api.IMdmSettings;
import ca.uhn.fhir.mdm.log.Logs;
import ca.uhn.fhir.mdm.model.MdmTransactionContext;
@ -39,6 +41,7 @@ import ca.uhn.fhir.rest.server.TransactionLogMessages;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.messaging.ResourceOperationMessage;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IBaseBundle;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
@ -81,7 +84,7 @@ public class MdmMessageHandler implements MessageHandler {
ResourceModifiedMessage msg = ((ResourceModifiedJsonMessage) theMessage).getPayload();
try {
IBaseResource sourceResource = msg.getNewPayload(myFhirContext);
IBaseResource sourceResource = extractSourceResource(msg);
boolean toProcess = myMdmResourceFilteringSvc.shouldBeProcessed((IAnyResource) sourceResource);
if (toProcess) {
@ -93,6 +96,15 @@ public class MdmMessageHandler implements MessageHandler {
}
}
private IBaseResource extractSourceResource(ResourceModifiedMessage theResourceModifiedMessage) {
IBaseResource sourceResource = theResourceModifiedMessage.getNewPayload(myFhirContext);
if (myFhirContext.getVersion().getVersion() == FhirVersionEnum.R5 && sourceResource instanceof IBaseBundle) {
return SubscriptionTopicUtil.extractResourceFromBundle(myFhirContext, (IBaseBundle) sourceResource);
} else {
return sourceResource;
}
}
private void matchMdmAndUpdateLinks(IBaseResource theSourceResource, ResourceModifiedMessage theMsg) {
String resourceType = theSourceResource.getIdElement().getResourceType();

View File

@ -27,9 +27,12 @@ import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
import ca.uhn.fhir.jpa.subscription.channel.api.ChannelProducerSettings;
import ca.uhn.fhir.jpa.subscription.channel.subscription.IChannelNamer;
import ca.uhn.fhir.jpa.subscription.match.registry.SubscriptionLoader;
import ca.uhn.fhir.jpa.subscription.model.CanonicalSubscriptionChannelType;
import ca.uhn.fhir.jpa.topic.SubscriptionTopicLoader;
import ca.uhn.fhir.mdm.api.IMdmSettings;
import ca.uhn.fhir.mdm.api.MdmConstants;
import ca.uhn.fhir.mdm.log.Logs;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
@ -37,17 +40,21 @@ import ca.uhn.fhir.util.HapiExtensions;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.r4.model.BooleanType;
import org.hl7.fhir.r4.model.Subscription;
import org.hl7.fhir.r5.model.Coding;
import org.hl7.fhir.r5.model.Enumerations;
import org.hl7.fhir.r5.model.SubscriptionTopic;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class MdmSubscriptionLoader {
public static final String MDM_SUBSCIPRION_ID_PREFIX = "mdm-";
public static final String MDM_SUBSCRIPTION_ID_PREFIX = "mdm-";
private static final Logger ourLog = Logs.getMdmTroubleshootingLog();
@Autowired
@ -65,7 +72,11 @@ public class MdmSubscriptionLoader {
@Autowired
private IMdmSettings myMdmSettings;
@Autowired(required = false)
private SubscriptionTopicLoader mySubscriptionTopicLoader;
private IFhirResourceDao<IBaseResource> mySubscriptionDao;
private IFhirResourceDao<SubscriptionTopic> mySubscriptionTopicDao;
public synchronized void daoUpdateMdmSubscriptions() {
List<IBaseResource> subscriptions;
@ -73,16 +84,24 @@ public class MdmSubscriptionLoader {
switch (myFhirContext.getVersion().getVersion()) {
case DSTU3:
subscriptions = mdmResourceTypes.stream()
.map(resourceType ->
buildMdmSubscriptionDstu3(MDM_SUBSCIPRION_ID_PREFIX + resourceType, resourceType + "?"))
.map(resourceType -> buildMdmSubscriptionDstu3(
MDM_SUBSCRIPTION_ID_PREFIX + resourceType, resourceType + "?"))
.collect(Collectors.toList());
break;
case R4:
subscriptions = mdmResourceTypes.stream()
.map(resourceType ->
buildMdmSubscriptionR4(MDM_SUBSCIPRION_ID_PREFIX + resourceType, resourceType + "?"))
buildMdmSubscriptionR4(MDM_SUBSCRIPTION_ID_PREFIX + resourceType, resourceType + "?"))
.collect(Collectors.toList());
break;
case R5:
SubscriptionTopic subscriptionTopic = buildMdmSubscriptionTopicR5(mdmResourceTypes);
updateSubscriptionTopic(subscriptionTopic);
// After loading subscriptionTopic, sync subscriptionTopic to the registry.
mySubscriptionTopicLoader.syncDatabaseToCache();
subscriptions = buildMdmSubscriptionR5(subscriptionTopic);
break;
default:
throw new ConfigurationException(Msg.code(736) + "MDM not supported for FHIR version "
+ myFhirContext.getVersion().getVersion());
@ -107,6 +126,11 @@ public class MdmSubscriptionLoader {
}
}
synchronized void updateSubscriptionTopic(SubscriptionTopic theSubscriptionTopic) {
mySubscriptionTopicDao = myDaoRegistry.getResourceDao("SubscriptionTopic");
mySubscriptionTopicDao.update(theSubscriptionTopic, SystemRequestDetails.forAllPartitions());
}
private org.hl7.fhir.dstu3.model.Subscription buildMdmSubscriptionDstu3(String theId, String theCriteria) {
org.hl7.fhir.dstu3.model.Subscription retval = new org.hl7.fhir.dstu3.model.Subscription();
retval.setId(theId);
@ -124,7 +148,7 @@ public class MdmSubscriptionLoader {
channel.setType(org.hl7.fhir.dstu3.model.Subscription.SubscriptionChannelType.MESSAGE);
channel.setEndpoint("channel:"
+ myChannelNamer.getChannelName(IMdmSettings.EMPI_CHANNEL_NAME, new ChannelProducerSettings()));
channel.setPayload("application/json");
channel.setPayload(Constants.CT_JSON);
return retval;
}
@ -145,7 +169,56 @@ public class MdmSubscriptionLoader {
channel.setType(Subscription.SubscriptionChannelType.MESSAGE);
channel.setEndpoint("channel:"
+ myChannelNamer.getChannelName(IMdmSettings.EMPI_CHANNEL_NAME, new ChannelProducerSettings()));
channel.setPayload("application/json");
channel.setPayload(Constants.CT_JSON);
return retval;
}
private SubscriptionTopic buildMdmSubscriptionTopicR5(List<String> theMdmResourceTypes) {
SubscriptionTopic subscriptionTopic = new SubscriptionTopic();
subscriptionTopic.setId(MDM_SUBSCRIPTION_ID_PREFIX + "subscription-topic");
subscriptionTopic
.getMeta()
.addTag()
.setSystem(MdmConstants.SYSTEM_MDM_MANAGED)
.setCode(MdmConstants.CODE_HAPI_MDM_MANAGED);
subscriptionTopic.setStatus(Enumerations.PublicationStatus.ACTIVE);
subscriptionTopic.setUrl(MdmConstants.SUBSCRIPTION_TOPIC_URL);
theMdmResourceTypes.forEach(
resourceType -> buildSubscriptionTopicResourceTriggerComponent(resourceType, subscriptionTopic));
return subscriptionTopic;
}
private static void buildSubscriptionTopicResourceTriggerComponent(
String theResourceType, SubscriptionTopic theSubscriptionTopic) {
SubscriptionTopic.SubscriptionTopicResourceTriggerComponent triggerComponent =
theSubscriptionTopic.addResourceTrigger();
triggerComponent.setResource(theResourceType);
triggerComponent.addSupportedInteraction(SubscriptionTopic.InteractionTrigger.CREATE);
triggerComponent.addSupportedInteraction(SubscriptionTopic.InteractionTrigger.UPDATE);
}
private List<IBaseResource> buildMdmSubscriptionR5(SubscriptionTopic theSubscriptionTopic) {
org.hl7.fhir.r5.model.Subscription subscription = new org.hl7.fhir.r5.model.Subscription();
subscription.setId(MDM_SUBSCRIPTION_ID_PREFIX + "subscription");
subscription.setReason("MDM");
subscription.setStatus(Enumerations.SubscriptionStatusCodes.REQUESTED);
subscription.setTopic(theSubscriptionTopic.getUrl());
subscription
.getMeta()
.addTag()
.setSystem(MdmConstants.SYSTEM_MDM_MANAGED)
.setCode(MdmConstants.CODE_HAPI_MDM_MANAGED);
subscription.setChannelType(new Coding()
.setCode(CanonicalSubscriptionChannelType.MESSAGE.toCode())
.setSystem(CanonicalSubscriptionChannelType.MESSAGE.getSystem()));
subscription.setEndpoint("channel:"
+ myChannelNamer.getChannelName(IMdmSettings.EMPI_CHANNEL_NAME, new ChannelProducerSettings()));
subscription.setContentType(Constants.CT_JSON);
return Collections.singletonList(subscription);
}
}

View File

@ -0,0 +1,95 @@
package ca.uhn.fhir.jpa.mdm.config;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
import ca.uhn.fhir.jpa.subscription.channel.subscription.IChannelNamer;
import ca.uhn.fhir.jpa.subscription.match.registry.SubscriptionLoader;
import ca.uhn.fhir.jpa.topic.SubscriptionTopicLoader;
import ca.uhn.fhir.mdm.api.IMdmSettings;
import ca.uhn.fhir.mdm.rules.json.MdmRulesJson;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.r5.model.Subscription;
import org.hl7.fhir.r5.model.SubscriptionTopic;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.junit.jupiter.MockitoExtension;
import java.util.Arrays;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class MdmSubscriptionLoaderR5Test {
@Mock
IFhirResourceDao<IBaseResource> mySubscriptionDao;
@Mock
IFhirResourceDao<SubscriptionTopic> mySubscriptionTopicDao;
@Mock
DaoRegistry myDaoRegistry;
@Mock
IMdmSettings myMdmSettings;
@Spy
FhirContext myFhirContext = FhirContext.forR5Cached();
@Mock
IChannelNamer myChannelNamer;
@Mock
SubscriptionLoader mySubscriptionLoader;
@Mock
SubscriptionTopicLoader mySubscriptionTopicLoader;
@InjectMocks
MdmSubscriptionLoader mySvc = new MdmSubscriptionLoader();
@AfterEach
public void after() {
verifyNoMoreInteractions(mySubscriptionTopicDao);
}
@Test
public void testDaoUpdateMdmSubscriptions_withR5FhirContext_createsCorrectSubscriptions() {
// setup
MdmRulesJson mdmRulesJson = new MdmRulesJson();
mdmRulesJson.setMdmTypes(Arrays.asList("Patient"));
when(myMdmSettings.getMdmRules()).thenReturn(mdmRulesJson);
when(myChannelNamer.getChannelName(any(), any())).thenReturn("Test");
when(myDaoRegistry.getResourceDao(eq("Subscription"))).thenReturn(mySubscriptionDao);
when(myDaoRegistry.getResourceDao(eq("SubscriptionTopic"))).thenReturn(mySubscriptionTopicDao);
when(mySubscriptionDao.read(any(), any(RequestDetails.class))).thenThrow(new ResourceGoneException(""));
// execute
mySvc.daoUpdateMdmSubscriptions();
// verify SubscriptionTopic
ArgumentCaptor<SubscriptionTopic> subscriptionTopicCaptor = ArgumentCaptor.forClass(SubscriptionTopic.class);
verify(mySubscriptionTopicDao).update(subscriptionTopicCaptor.capture(), any(RequestDetails.class));
SubscriptionTopic subscriptionTopic = subscriptionTopicCaptor.getValue();
assertNotNull(subscriptionTopic);
assertEquals("mdm-subscription-topic", subscriptionTopic.getId());
assertEquals(1, subscriptionTopic.getResourceTrigger().size());
SubscriptionTopic.SubscriptionTopicResourceTriggerComponent triggerComponent = subscriptionTopic.getResourceTrigger().get(0);
assertEquals("Patient", triggerComponent.getResource());
// verify Subscription
ArgumentCaptor<Subscription> subscriptionCaptor = ArgumentCaptor.forClass(Subscription.class);
verify(mySubscriptionDao).update(subscriptionCaptor.capture(), any(RequestDetails.class));
Subscription subscription = subscriptionCaptor.getValue();
assertNotNull(subscription);
assertEquals("mdm-subscription", subscription.getId());
}
}

View File

@ -22,39 +22,74 @@ package ca.uhn.fhir.jpa.topic;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
import ca.uhn.fhir.jpa.searchparam.matcher.SearchParamMatcher;
import ca.uhn.fhir.jpa.subscription.match.matcher.matching.SubscriptionStrategyEvaluator;
import ca.uhn.fhir.jpa.subscription.submit.interceptor.SubscriptionQueryValidator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Lazy;
public class SubscriptionTopicConfig {
@Bean
SubscriptionTopicMatchingSubscriber subscriptionTopicMatchingSubscriber(FhirContext theFhirContext) {
return new SubscriptionTopicMatchingSubscriber(theFhirContext);
switch (theFhirContext.getVersion().getVersion()) {
case R5:
case R4B:
return new SubscriptionTopicMatchingSubscriber(theFhirContext);
default:
return null;
}
}
@Bean
@Lazy
SubscriptionTopicRegistry subscriptionTopicRegistry() {
return new SubscriptionTopicRegistry();
}
@Bean
@Lazy
SubscriptionTopicSupport subscriptionTopicSupport(
FhirContext theFhirContext, DaoRegistry theDaoRegistry, SearchParamMatcher theSearchParamMatcher) {
return new SubscriptionTopicSupport(theFhirContext, theDaoRegistry, theSearchParamMatcher);
}
@Bean
SubscriptionTopicLoader subscriptionTopicLoader() {
return new SubscriptionTopicLoader();
SubscriptionTopicLoader subscriptionTopicLoader(FhirContext theFhirContext) {
switch (theFhirContext.getVersion().getVersion()) {
case R5:
case R4B:
return new SubscriptionTopicLoader();
default:
return null;
}
}
@Bean
SubscriptionTopicRegisteringSubscriber subscriptionTopicRegisteringSubscriber() {
return new SubscriptionTopicRegisteringSubscriber();
SubscriptionTopicRegisteringSubscriber subscriptionTopicRegisteringSubscriber(FhirContext theFhirContext) {
switch (theFhirContext.getVersion().getVersion()) {
case R5:
case R4B:
return new SubscriptionTopicRegisteringSubscriber();
default:
return null;
}
}
@Bean
@Lazy
public SubscriptionQueryValidator subscriptionQueryValidator(
DaoRegistry theDaoRegistry, SubscriptionStrategyEvaluator theSubscriptionStrategyEvaluator) {
return new SubscriptionQueryValidator(theDaoRegistry, theSubscriptionStrategyEvaluator);
}
@Bean
SubscriptionTopicValidatingInterceptor subscriptionTopicValidatingInterceptor(
FhirContext theFhirContext, SubscriptionQueryValidator theSubscriptionQueryValidator) {
return new SubscriptionTopicValidatingInterceptor(theFhirContext, theSubscriptionQueryValidator);
switch (theFhirContext.getVersion().getVersion()) {
case R5:
case R4B:
return new SubscriptionTopicValidatingInterceptor(theFhirContext, theSubscriptionQueryValidator);
default:
return null;
}
}
}

View File

@ -24,8 +24,6 @@ import ca.uhn.fhir.interceptor.api.HookParams;
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
import ca.uhn.fhir.interceptor.api.Pointcut;
import ca.uhn.fhir.jpa.searchparam.matcher.InMemoryMatchResult;
import ca.uhn.fhir.jpa.subscription.match.matcher.subscriber.SubscriptionMatchDeliverer;
import ca.uhn.fhir.jpa.subscription.match.registry.SubscriptionRegistry;
import ca.uhn.fhir.jpa.subscription.model.ResourceModifiedJsonMessage;
import ca.uhn.fhir.jpa.subscription.model.ResourceModifiedMessage;
import ca.uhn.fhir.jpa.topic.filter.InMemoryTopicFilterMatcher;
@ -57,15 +55,6 @@ public class SubscriptionTopicMatchingSubscriber implements MessageHandler {
@Autowired
SubscriptionTopicRegistry mySubscriptionTopicRegistry;
@Autowired
SubscriptionRegistry mySubscriptionRegistry;
@Autowired
SubscriptionMatchDeliverer mySubscriptionMatchDeliverer;
@Autowired
SubscriptionTopicPayloadBuilder mySubscriptionTopicPayloadBuilder;
@Autowired
private IInterceptorBroadcaster myInterceptorBroadcaster;

View File

@ -19,11 +19,19 @@
*/
package ca.uhn.fhir.jpa.topic;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.subscription.model.ResourceModifiedJsonMessage;
import ca.uhn.fhir.rest.server.messaging.BaseResourceMessage;
import ca.uhn.fhir.util.BundleUtil;
import org.hl7.fhir.instance.model.api.IBaseBundle;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.r5.model.BaseReference;
import org.hl7.fhir.r5.model.Enumeration;
import org.hl7.fhir.r5.model.SubscriptionStatus;
import org.hl7.fhir.r5.model.SubscriptionTopic;
import java.util.List;
import java.util.Objects;
public class SubscriptionTopicUtil {
public static boolean matches(
@ -45,4 +53,23 @@ public class SubscriptionTopicUtil {
}
return false;
}
/**
* Extracts source resource from bundle contained in {@link ResourceModifiedJsonMessage} payload.
* Used for R5 resource modified message handling.
*/
public static IBaseResource extractResourceFromBundle(FhirContext myFhirContext, IBaseBundle theBundle) {
List<IBaseResource> resources = BundleUtil.toListOfResources(myFhirContext, theBundle);
return resources.stream()
.filter(SubscriptionStatus.class::isInstance)
.map(SubscriptionStatus.class::cast)
.flatMap(subscriptionStatus -> subscriptionStatus.getNotificationEvent().stream())
.filter(SubscriptionStatus.SubscriptionStatusNotificationEventComponent::hasFocus)
.map(SubscriptionStatus.SubscriptionStatusNotificationEventComponent::getFocus)
.map(BaseReference::getResource)
.filter(Objects::nonNull)
.findFirst()
.orElse(null);
}
}

View File

@ -1,16 +1,28 @@
package ca.uhn.fhir.jpa.topic;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.server.messaging.BaseResourceMessage;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.r5.model.Bundle;
import org.hl7.fhir.r5.model.Enumeration;
import org.hl7.fhir.r5.model.Patient;
import org.hl7.fhir.r5.model.Reference;
import org.hl7.fhir.r5.model.Resource;
import org.hl7.fhir.r5.model.SubscriptionStatus;
import org.hl7.fhir.r5.model.SubscriptionTopic;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
class SubscriptionTopicUtilTest {
private final FhirContext myContext = FhirContext.forR5Cached();
@Test
public void testMatch() {
// I know this is gross. I haven't found a nicer way to do this
@ -28,4 +40,50 @@ class SubscriptionTopicUtilTest {
assertFalse(SubscriptionTopicUtil.matches(BaseResourceMessage.OperationTypeEnum.TRANSACTION, supportedTypes));
}
@Test
public void testExtractResourceFromBundle_withCorrectBundle_returnsCorrectResource() {
Patient patient = new Patient();
patient.setId("Patient/1");
Bundle bundle = buildSubscriptionStatus(patient);
IBaseResource extractionResult = SubscriptionTopicUtil.extractResourceFromBundle(myContext, bundle);
assertEquals(patient, extractionResult);
}
@Test
public void testExtractResourceFromBundle_withoutReferenceResource_returnsNull() {
Bundle bundle = buildSubscriptionStatus(null);
IBaseResource extractionResult = SubscriptionTopicUtil.extractResourceFromBundle(myContext, bundle);
assertNull(extractionResult);
}
private Bundle buildSubscriptionStatus(Resource theResource) {
SubscriptionStatus subscriptionStatus = new SubscriptionStatus();
SubscriptionStatus.SubscriptionStatusNotificationEventComponent event =
subscriptionStatus.addNotificationEvent();
Reference reference = new Reference();
reference.setResource(theResource);
event.setFocus(reference);
Bundle bundle = new Bundle();
bundle.addEntry().setResource(subscriptionStatus);
bundle.addEntry().setResource(theResource);
return bundle;
}
@Test
public void testExtractResourceFromBundle_withoutNotificationEvent_returnsNull() {
Bundle bundle = new Bundle();
bundle.addEntry().setResource(new SubscriptionStatus());
IBaseResource extractionResult = SubscriptionTopicUtil.extractResourceFromBundle(myContext, bundle);
assertNull(extractionResult);
}
@Test
public void testExtractResourceFromBundle_withEmptyBundle_returnsNull() {
IBaseResource extractionResult = SubscriptionTopicUtil.extractResourceFromBundle(myContext, new Bundle());
assertNull(extractionResult);
}
}

View File

@ -45,6 +45,7 @@ public class MdmConstants {
"http://hl7.org/fhir/StructureDefinition/match-grade";
public static final String SYSTEM_GOLDEN_RECORD_STATUS = "http://hapifhir.io/fhir/NamingSystem/mdm-record-status";
public static final String SUBSCRIPTION_TOPIC_URL = "http://hapifhir.io/fhir/r5/SubscriptionTopic/mdm";
public static final String CODE_GOLDEN_RECORD = "GOLDEN_RECORD";
public static final String CODE_GOLDEN_RECORD_REDIRECTED = "REDIRECTED";
public static final String DISPLAY_GOLDEN_RECORD = "Golden Record";

View File

@ -82,6 +82,13 @@ public class CanonicalEID {
.setValue(myValue);
}
public org.hl7.fhir.r5.model.Identifier toR5() {
return new org.hl7.fhir.r5.model.Identifier()
.setUse(org.hl7.fhir.r5.model.Identifier.IdentifierUse.fromCode(myUse))
.setSystem(mySystem)
.setValue(myValue);
}
public String getSystem() {
return mySystem;
}

View File

@ -66,6 +66,7 @@ public class MdmProviderLoader {
switch (myFhirContext.getVersion().getVersion()) {
case DSTU3:
case R4:
case R5:
myResourceProviderFactory.addSupplier(() -> new MdmProviderDstu3Plus(
myFhirContext,
myMdmControllerSvc,

View File

@ -49,6 +49,10 @@ public class DateTimeWrapper {
org.hl7.fhir.r4.model.BaseDateTimeType r4Date = (org.hl7.fhir.r4.model.BaseDateTimeType) theDate;
myPrecision = r4Date.getPrecision();
myValueAsString = r4Date.getValueAsString();
} else if (theDate instanceof org.hl7.fhir.r5.model.BaseDateTimeType) {
org.hl7.fhir.r5.model.BaseDateTimeType r5Date = (org.hl7.fhir.r5.model.BaseDateTimeType) theDate;
myPrecision = r5Date.getPrecision();
myValueAsString = r5Date.getValueAsString();
} else {
// we should consider changing this error so we don't need the fhir context at all
throw new UnsupportedOperationException(Msg.code(1520) + "Version not supported: "

View File

@ -50,6 +50,7 @@ import javax.annotation.Nonnull;
import static ca.uhn.fhir.context.FhirVersionEnum.DSTU3;
import static ca.uhn.fhir.context.FhirVersionEnum.R4;
import static ca.uhn.fhir.context.FhirVersionEnum.R5;
@Service
public class GoldenResourceHelper {
@ -200,7 +201,7 @@ public class GoldenResourceHelper {
private void validateContextSupported() {
FhirVersionEnum fhirVersion = myFhirContext.getVersion().getVersion();
if (fhirVersion == R4 || fhirVersion == DSTU3) {
if (fhirVersion == R4 || fhirVersion == DSTU3 || fhirVersion == R5) {
return;
}
throw new UnsupportedOperationException(Msg.code(1489) + "Version not supported: "

View File

@ -56,10 +56,12 @@ public final class IdentifierUtil {
* @param theFhirContext FHIR context to use for determining the identifier version
* @param eid EID to get equivalent FHIR Identifier from
* @param <T> Generic Identifier base interface
* @return Returns appropriate R4 or DSTU3 Identifier instance
* @return Returns appropriate R5, R4 or DSTU3 Identifier instance
*/
public static <T extends IBase> T toId(FhirContext theFhirContext, CanonicalEID eid) {
switch (theFhirContext.getVersion().getVersion()) {
case R5:
return (T) eid.toR5();
case R4:
return (T) eid.toR4();
case DSTU3: