diff --git a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/extractor/ResourceIndexedSearchParams.java b/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/extractor/ResourceIndexedSearchParams.java index 61770fc83c5..a2a3bac6fcd 100644 --- a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/extractor/ResourceIndexedSearchParams.java +++ b/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/extractor/ResourceIndexedSearchParams.java @@ -282,9 +282,7 @@ public final class ResourceIndexedSearchParams { } else { ForcedId forcedId = target.getForcedId(); if (forcedId != null) { - // TODO KHS is forcedId.getForcedId().equals(theReference.getIdPart() also valid? - return forcedId.getForcedId().equals(theReference.getValue()) || - forcedId.getForcedId().equals(theReference.getIdPart()); + return forcedId.getForcedId().equals(theReference.getValue()); } else { return false; } diff --git a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/matcher/InMemoryResourceMatcher.java b/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/matcher/InMemoryResourceMatcher.java index e7c509de7eb..6ec9d7ec244 100644 --- a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/matcher/InMemoryResourceMatcher.java +++ b/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/matcher/InMemoryResourceMatcher.java @@ -23,12 +23,14 @@ package ca.uhn.fhir.jpa.searchparam.matcher; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.RuntimeResourceDefinition; import ca.uhn.fhir.context.RuntimeSearchParam; +import ca.uhn.fhir.jpa.model.entity.ModelConfig; import ca.uhn.fhir.jpa.searchparam.MatchUrlService; import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; import ca.uhn.fhir.jpa.searchparam.extractor.ResourceIndexedSearchParams; import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry; import ca.uhn.fhir.jpa.searchparam.util.SourceParam; import ca.uhn.fhir.model.api.IQueryParameterType; +import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.rest.api.Constants; import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum; import ca.uhn.fhir.rest.param.BaseParamWithPrefix; @@ -56,6 +58,8 @@ public class InMemoryResourceMatcher { @Autowired ISearchParamRegistry mySearchParamRegistry; @Autowired + ModelConfig myModelConfig; + @Autowired FhirContext myFhirContext; /** @@ -212,9 +216,29 @@ public class InMemoryResourceMatcher { } private boolean matchParams(String theResourceName, String theParamName, RuntimeSearchParam paramDef, List theNextAnd, ResourceIndexedSearchParams theSearchParams) { + if (paramDef.getParamType() == RestSearchParameterTypeEnum.REFERENCE) { + stripBaseUrlsFromReferenceParams(theNextAnd); + } return theNextAnd.stream().anyMatch(token -> theSearchParams.matchParam(theResourceName, theParamName, paramDef, token)); } + private void stripBaseUrlsFromReferenceParams(List theNextAnd) { + if (myModelConfig.getTreatBaseUrlsAsLocal().isEmpty()) { + return; + } + + for (IQueryParameterType param : theNextAnd) { + ReferenceParam ref = (ReferenceParam) param; + IIdType dt = new IdDt(ref.getBaseUrl(), ref.getResourceType(), ref.getIdPart(), null); + + if (dt.hasBaseUrl()) { + if (myModelConfig.getTreatBaseUrlsAsLocal().contains(dt.getBaseUrl())) { + ref.setValue(dt.toUnqualified().getValue()); + } + } + } + } + private boolean hasChain(List> theAndOrParams) { return theAndOrParams.stream().flatMap(List::stream).anyMatch(param -> param instanceof ReferenceParam && ((ReferenceParam) param).getChain() != null); } 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 bc653ef7a3b..2a80eb7686e 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 @@ -2,6 +2,7 @@ package ca.uhn.fhir.jpa.searchparam.matcher; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.RuntimeSearchParam; +import ca.uhn.fhir.jpa.model.entity.ModelConfig; import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate; import ca.uhn.fhir.jpa.searchparam.MatchUrlService; import ca.uhn.fhir.jpa.searchparam.extractor.ResourceIndexedSearchParams; @@ -67,6 +68,11 @@ public class InMemoryResourceMatcherR5Test { FhirContext fhirContext() { return FhirContext.forR5(); } + + @Bean + ModelConfig modelConfig() { + return new ModelConfig(); + } } @Before diff --git a/hapi-fhir-jpaserver-subscription/src/test/java/ca/uhn/fhir/jpa/subscription/module/matcher/InMemorySubscriptionMatcherR3Test.java b/hapi-fhir-jpaserver-subscription/src/test/java/ca/uhn/fhir/jpa/subscription/module/matcher/InMemorySubscriptionMatcherR3Test.java index 6bc490b2c95..e5ded60c29e 100644 --- a/hapi-fhir-jpaserver-subscription/src/test/java/ca/uhn/fhir/jpa/subscription/module/matcher/InMemorySubscriptionMatcherR3Test.java +++ b/hapi-fhir-jpaserver-subscription/src/test/java/ca/uhn/fhir/jpa/subscription/module/matcher/InMemorySubscriptionMatcherR3Test.java @@ -1,18 +1,23 @@ package ca.uhn.fhir.jpa.subscription.module.matcher; +import ca.uhn.fhir.jpa.model.entity.ModelConfig; import ca.uhn.fhir.jpa.searchparam.matcher.InMemoryMatchResult; import ca.uhn.fhir.jpa.searchparam.matcher.SearchParamMatcher; import ca.uhn.fhir.jpa.subscription.module.BaseSubscriptionDstu3Test; import ca.uhn.fhir.rest.api.server.IBundleProvider; import ca.uhn.fhir.rest.server.SimpleBundleProvider; +import ca.uhn.fhir.util.UrlUtil; import org.hl7.fhir.dstu3.model.*; import org.hl7.fhir.dstu3.model.codesystems.MedicationRequestCategory; import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IIdType; +import org.junit.After; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; import java.util.Collections; +import java.util.HashSet; +import java.util.Set; import static org.junit.Assert.*; @@ -21,6 +26,8 @@ public class InMemorySubscriptionMatcherR3Test extends BaseSubscriptionDstu3Test SubscriptionStrategyEvaluator mySubscriptionStrategyEvaluator; @Autowired SearchParamMatcher mySearchParamMatcher; + @Autowired + ModelConfig myModelConfig; private void assertUnsupported(IBaseResource resource, String criteria) { assertFalse(mySearchParamMatcher.match(criteria, resource, null).supported()); @@ -48,6 +55,10 @@ public class InMemorySubscriptionMatcherR3Test extends BaseSubscriptionDstu3Test assertEquals(theSubscriptionMatchingStrategy, mySubscriptionStrategyEvaluator.determineStrategy(criteria)); } + @After + public void after() { + myModelConfig.setTreatBaseUrlsAsLocal(new ModelConfig().getTreatBaseUrlsAsLocal()); + } /** * Technically this is an invalid reference in most cases, but this shouldn't choke @@ -580,4 +591,35 @@ public class InMemorySubscriptionMatcherR3Test extends BaseSubscriptionDstu3Test assertNotMatched(observation, criteria); } + + @Test + public void testExternalReferenceMatches() { + String goodReference = "http://example.com/base/Organization/FOO"; + String goodCriteria = "Patient?organization=" + UrlUtil.escapeUrlParam(goodReference); + + String badReference1 = "http://example.com/bad/Organization/FOO"; + String badCriteria1 = "Patient?organization=" + UrlUtil.escapeUrlParam(badReference1); + + String badReference2 = "http://example.org/base/Organization/FOO"; + String badCriteria2 = "Patient?organization=" + UrlUtil.escapeUrlParam(badReference2); + + String badReference3 = "https://example.com/base/Organization/FOO"; + String badCriteria3 = "Patient?organization=" + UrlUtil.escapeUrlParam(badReference3); + + String badReference4 = "http://example.com/base/Organization/GOO"; + String badCriteria4 = "Patient?organization=" + UrlUtil.escapeUrlParam(badReference4); + + Set urls = new HashSet<>(); + urls.add("http://example.com/base/"); + myModelConfig.setTreatBaseUrlsAsLocal(urls); + + Patient patient = new Patient(); + patient.getManagingOrganization().setReference("Organization/FOO"); + + assertMatched(patient, goodCriteria); + assertNotMatched(patient, badCriteria1); + assertNotMatched(patient, badCriteria2); + assertNotMatched(patient, badCriteria3); + assertNotMatched(patient, badCriteria4); + } }