diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/5_2_0/2150-inmemory-null-source.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/5_2_0/2150-inmemory-null-source.yaml new file mode 100644 index 00000000000..9b0472a0efb --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/5_2_0/2150-inmemory-null-source.yaml @@ -0,0 +1,5 @@ +--- +type: fix +issue: 2150 +title: "The In Memory search matcher (used for Subscriptions) could crash if a subscription was registered using the + `_source` search parameter, and a resource was processed with no source value. This has been corrected." diff --git a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/util/SourceParam.java b/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/util/SourceParam.java index 938fcf6cb99..9ff5a50b881 100644 --- a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/util/SourceParam.java +++ b/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/util/SourceParam.java @@ -2,6 +2,7 @@ package ca.uhn.fhir.jpa.searchparam.util; import ca.uhn.fhir.rest.api.Constants; +import static org.apache.commons.lang3.StringUtils.defaultString; import static org.apache.commons.lang3.StringUtils.left; /* @@ -35,19 +36,19 @@ public class SourceParam { private final String myRequestId; public SourceParam(String theParameterValue) { - myParameterValue = theParameterValue; + myParameterValue = defaultString(theParameterValue); String requestId; - int lastHashValueIndex = theParameterValue.lastIndexOf('#'); + int lastHashValueIndex = myParameterValue.lastIndexOf('#'); if (lastHashValueIndex == -1) { - mySourceUri = theParameterValue; + mySourceUri = myParameterValue; requestId = null; } else { if (lastHashValueIndex == 0) { mySourceUri = null; } else { - mySourceUri = theParameterValue.substring(0, lastHashValueIndex); + mySourceUri = myParameterValue.substring(0, lastHashValueIndex); } - requestId = theParameterValue.substring(lastHashValueIndex + 1); + requestId = myParameterValue.substring(lastHashValueIndex + 1); } myRequestId = left(requestId, Constants.REQUEST_ID_LENGTH); } diff --git a/hapi-fhir-jpaserver-searchparam/src/test/java/ca/uhn/fhir/jpa/searchparam/matcher/InMemoryResourceMatcherR5Test.java b/hapi-fhir-jpaserver-searchparam/src/test/java/ca/uhn/fhir/jpa/searchparam/matcher/InMemoryResourceMatcherR5Test.java index e2cd7844f88..13d46785602 100644 --- a/hapi-fhir-jpaserver-searchparam/src/test/java/ca/uhn/fhir/jpa/searchparam/matcher/InMemoryResourceMatcherR5Test.java +++ b/hapi-fhir-jpaserver-searchparam/src/test/java/ca/uhn/fhir/jpa/searchparam/matcher/InMemoryResourceMatcherR5Test.java @@ -50,6 +50,7 @@ public class InMemoryResourceMatcherR5Test { private static final String SOURCE_URI = "urn:source:0"; private static final String REQUEST_ID = "a_request_id"; private static final String TEST_SOURCE = SOURCE_URI + "#" + REQUEST_ID; + @MockBean ISearchParamRegistry mySearchParamRegistry; @Autowired @@ -100,6 +101,27 @@ public class InMemoryResourceMatcherR5Test { } } + @Test + public void testSupportedSource_ResourceWithNoSourceValue() { + myObservation.getMeta().getSourceElement().setValue(null); + { + InMemoryMatchResult result = myInMemoryResourceMatcher.match(Constants.PARAM_SOURCE + "=" + TEST_SOURCE, myObservation, mySearchParams); + assertFalse(result.matched()); + } + { + InMemoryMatchResult result = myInMemoryResourceMatcher.match(Constants.PARAM_SOURCE + "=" + SOURCE_URI, myObservation, mySearchParams); + assertFalse(result.matched()); + } + { + InMemoryMatchResult result = myInMemoryResourceMatcher.match(Constants.PARAM_SOURCE + "=" + REQUEST_ID, myObservation, mySearchParams); + assertFalse(result.matched()); + } + { + InMemoryMatchResult result = myInMemoryResourceMatcher.match(Constants.PARAM_SOURCE + "=#" + REQUEST_ID, myObservation, mySearchParams); + assertFalse(result.matched()); + } + } + @Test public void testUnsupportedChained() { InMemoryMatchResult result = myInMemoryResourceMatcher.match("encounter.class=FOO", myObservation, mySearchParams); diff --git a/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/match/matcher/subscriber/MatchingQueueSubscriberLoader.java b/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/match/matcher/subscriber/MatchingQueueSubscriberLoader.java index 22ce2310775..72912f50234 100644 --- a/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/match/matcher/subscriber/MatchingQueueSubscriberLoader.java +++ b/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/match/matcher/subscriber/MatchingQueueSubscriberLoader.java @@ -4,11 +4,9 @@ import ca.uhn.fhir.jpa.subscription.channel.api.IChannelReceiver; import ca.uhn.fhir.jpa.subscription.channel.subscription.SubscriptionChannelFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.context.event.EventListener; -import org.springframework.messaging.SubscribableChannel; import javax.annotation.PreDestroy; @@ -35,8 +33,8 @@ import static ca.uhn.fhir.jpa.subscription.match.matcher.subscriber.Subscription */ public class MatchingQueueSubscriberLoader { + protected IChannelReceiver myMatchingChannel; private Logger ourLog = LoggerFactory.getLogger(MatchingQueueSubscriberLoader.class); - @Autowired private SubscriptionMatchingSubscriber mySubscriptionMatchingSubscriber; @Autowired @@ -46,8 +44,6 @@ public class MatchingQueueSubscriberLoader { @Autowired private SubscriptionActivatingSubscriber mySubscriptionActivatingSubscriber; - protected IChannelReceiver myMatchingChannel; - @EventListener(classes = {ContextRefreshedEvent.class}) public void handleContextRefreshEvent() { if (myMatchingChannel == null) {