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:
parent
f624cf75ad
commit
a1aa9c4a36
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
type: add
|
||||
issue: 5081
|
||||
title: "Added MDM support for FHIR R5."
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -66,6 +66,7 @@ public class MdmProviderLoader {
|
|||
switch (myFhirContext.getVersion().getVersion()) {
|
||||
case DSTU3:
|
||||
case R4:
|
||||
case R5:
|
||||
myResourceProviderFactory.addSupplier(() -> new MdmProviderDstu3Plus(
|
||||
myFhirContext,
|
||||
myMdmControllerSvc,
|
||||
|
|
|
@ -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: "
|
||||
|
|
|
@ -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: "
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in New Issue