diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/interceptor/api/Pointcut.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/interceptor/api/Pointcut.java
index d5e9aa9a35b..837fc188567 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/interceptor/api/Pointcut.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/interceptor/api/Pointcut.java
@@ -1155,6 +1155,9 @@ public enum Pointcut implements IPointcut {
* pulled out of the servlet request. This parameter is identical to the RequestDetails parameter above but will
* only be populated when operating in a RestfulServer implementation. It is provided as a convenience.
*
+ *
+ * ca.uhn.fhir.jpa.searchparam.SearchParameterMap - Contains the details of the search being checked. This can be modified.
+ *
*
*
* Hooks should return void
.
@@ -1163,7 +1166,8 @@ public enum Pointcut implements IPointcut {
STORAGE_PRESEARCH_REGISTERED(void.class,
"ca.uhn.fhir.rest.server.util.ICachedSearchDetails",
"ca.uhn.fhir.rest.api.server.RequestDetails",
- "ca.uhn.fhir.rest.server.servlet.ServletRequestDetails"
+ "ca.uhn.fhir.rest.server.servlet.ServletRequestDetails",
+ "ca.uhn.fhir.jpa.searchparam.SearchParameterMap"
),
/**
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/api/Constants.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/api/Constants.java
index 93d957299d2..ef960acc0a2 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/api/Constants.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/api/Constants.java
@@ -200,6 +200,7 @@ public class Constants {
public static final String PARAMQUALIFIER_STRING_CONTAINS = ":contains";
public static final String PARAMQUALIFIER_STRING_EXACT = ":exact";
public static final String PARAMQUALIFIER_TOKEN_TEXT = ":text";
+ public static final String PARAMQUALIFIER_MDM = ":mdm";
public static final int STATUS_HTTP_200_OK = 200;
public static final int STATUS_HTTP_201_CREATED = 201;
public static final int STATUS_HTTP_204_NO_CONTENT = 204;
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/ReferenceParam.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/ReferenceParam.java
index a8c43a708bd..583edaa6731 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/ReferenceParam.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/ReferenceParam.java
@@ -22,6 +22,7 @@ package ca.uhn.fhir.rest.param;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.primitive.IdDt;
+import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.util.CoverageIgnore;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
@@ -41,6 +42,7 @@ public class ReferenceParam extends BaseParam /*implements IQueryParameterType*/
private String myBaseUrl;
private String myValue;
private String myIdPart;
+ private Boolean myMdmExpand;
/**
* Constructor
@@ -121,6 +123,11 @@ public class ReferenceParam extends BaseParam /*implements IQueryParameterType*/
@Override
void doSetValueAsQueryToken(FhirContext theContext, String theParamName, String theQualifier, String theValue) {
+ if (Constants.PARAMQUALIFIER_MDM.equals(theQualifier)) {
+ myMdmExpand = true;
+ theQualifier = "";
+ //TODO GGG i probably have to deal with chaining here? like refusing the mdm qualifier if i can detect its chained?
+ }
String q = theQualifier;
if (isNotBlank(q)) {
if (q.startsWith(":")) {
@@ -166,6 +173,14 @@ public class ReferenceParam extends BaseParam /*implements IQueryParameterType*/
return myBaseUrl;
}
+ public boolean isMdmExpand() {
+ return myMdmExpand != null && myMdmExpand;
+ }
+
+ public ReferenceParam setMdmExpand(boolean theMdmExpand) {
+ myMdmExpand = theMdmExpand;
+ return this;
+ }
public String getChain() {
return myChain;
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/BaseConfig.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/BaseConfig.java
index 6ef6a72f468..55617d7b2a2 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/BaseConfig.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/BaseConfig.java
@@ -40,6 +40,7 @@ import ca.uhn.fhir.jpa.dao.index.DaoResourceLinkResolver;
import ca.uhn.fhir.jpa.dao.index.DaoSearchParamSynchronizer;
import ca.uhn.fhir.jpa.dao.index.IdHelperService;
import ca.uhn.fhir.jpa.dao.index.SearchParamWithInlineReferencesExtractor;
+import ca.uhn.fhir.jpa.dao.mdm.MdmLinkExpandSvc;
import ca.uhn.fhir.jpa.dao.predicate.PredicateBuilder;
import ca.uhn.fhir.jpa.dao.predicate.PredicateBuilderCoords;
import ca.uhn.fhir.jpa.dao.predicate.PredicateBuilderDate;
@@ -459,11 +460,15 @@ public abstract class BaseConfig {
}
@Bean
- @Lazy
public MdmSearchExpandingInterceptorInterceptor mdmSearchExpandingInterceptorInterceptor() {
return new MdmSearchExpandingInterceptorInterceptor();
}
+ @Bean
+ public MdmLinkExpandSvc myMdmLinkExpandSvc() {
+ return new MdmLinkExpandSvc();
+ }
+
@Bean
@Lazy
public TerminologyUploaderProvider terminologyUploaderProvider() {
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/interceptor/MdmSearchExpandingInterceptorInterceptor.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/interceptor/MdmSearchExpandingInterceptorInterceptor.java
index 64762d566c2..04333b578a7 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/interceptor/MdmSearchExpandingInterceptorInterceptor.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/interceptor/MdmSearchExpandingInterceptorInterceptor.java
@@ -35,6 +35,7 @@ import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.api.server.RequestDetails;
+import ca.uhn.fhir.rest.param.ReferenceParam;
import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.util.ClasspathUtil;
import org.apache.commons.lang3.Validate;
@@ -62,44 +63,21 @@ public class MdmSearchExpandingInterceptorInterceptor {
@Autowired
private MdmLinkExpandSvc myMdmLinkExpandSvc;
@Autowired
- private SearchParamHelper mySearchParamHelper;
- @Autowired
private FhirContext myFhirContext;
@Autowired
private IdHelperService myIdHelperService;
- @Hook(Pointcut.STORAGE_PRECHECK_FOR_CACHED_SEARCH)
- public boolean hook(RequestDetails theRequestDetails, SearchParameterMap theSearchParameterMap) {
- Map parameters =theRequestDetails.getParameters();
- boolean shouldExpandMdm = false;
- if (parameters.containsKey("_mdm")) {
- shouldExpandMdm = parameters.get("_mdm").length == 1 && parameters.get("_mdm")[0].equalsIgnoreCase("true");
- }
- if (shouldExpandMdm) {
- ourLog.debug("Detected that incoming request has _mdm=true. The request was: {}", theRequestDetails.getRequestPath());
- String resourceName = theRequestDetails.getResourceName();
- Collection patientSearchParams = mySearchParamHelper.getPatientSearchParamsForResourceType(resourceName);
- ourLog.debug("Resource type {} has patient search parameters [{}]", resourceName, patientSearchParams.stream().map(RuntimeSearchParam::getName).collect(Collectors.joining(", ")));
- for (RuntimeSearchParam patientSearchParam: patientSearchParams) {
- if (!theSearchParameterMap.containsKey(patientSearchParam.getName())) {
- continue;
- }
- List> lists = theSearchParameterMap.get(patientSearchParam.getName());
- for (List list : lists) {
- List toAdd = new ArrayList<>();
- for (IQueryParameterType paramVal : list) {
- if (!paramVal.getMissing() && paramVal.getQueryParameterQualifier().equalsIgnoreCase("equals")){
- String valueAsQueryToken = paramVal.getValueAsQueryToken(myFhirContext);
- Long pidOrThrowException = myIdHelperService.getPidOrThrowException(new IdDt(valueAsQueryToken));
- Set expandedIds= myMdmLinkExpandSvc.expandMdmBySourceResourcePid(pidOrThrowException);
- ourLog.info("Expanded to resource ids: [{}]", String.join(",", expandedIds));
- toAdd.addAll(expandedIds.stream().map(StringParam::new).collect(Collectors.toList()));
- }
- }
- list.addAll(toAdd);
- }
- }
- }
- return true;
+ @Hook(Pointcut.STORAGE_PRESEARCH_REGISTERED)
+ public void hook(RequestDetails theRequestDetails, SearchParameterMap theSearchParameterMap) {
+ System.out.println("zoop");
+ theSearchParameterMap.values().stream()
+ .flatMap(Collection::stream)
+ .filter(queryParam -> queryParam instanceof ReferenceParam)
+ .filter(referenceParam -> ((ReferenceParam) referenceParam).isMdmExpand())
+ .map(untypedParam -> (ReferenceParam)untypedParam)
+ .forEach(mdmReferenceParam -> {
+ System.out.println("zoop");
+ System.out.println(mdmReferenceParam.toString());
+ });
}
}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/SearchCoordinatorSvcImpl.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/SearchCoordinatorSvcImpl.java
index 6786f9ff002..10a03f5c765 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/SearchCoordinatorSvcImpl.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/SearchCoordinatorSvcImpl.java
@@ -307,6 +307,13 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
ourLog.debug("Registering new search {}", searchUuid);
+ // Interceptor call: STORAGE_PRESEARCH_REGISTERED
+ HookParams params = new HookParams()
+ .add(ICachedSearchDetails.class, search)
+ .add(RequestDetails.class, theRequestDetails)
+ .addIfMatchesType(ServletRequestDetails.class, theRequestDetails)
+ .add(SearchParameterMap.class, theParams);
+ JpaInterceptorBroadcaster.doCallHooks(myInterceptorBroadcaster, theRequestDetails, Pointcut.STORAGE_PRESEARCH_REGISTERED, params);
Class extends IBaseResource> resourceTypeClass = myContext.getResourceDefinition(theResourceType).getImplementingClass();
final ISearchBuilder sb = mySearchBuilderFactory.newSearchBuilder(theCallingDao, theResourceType, resourceTypeClass);
sb.setFetchSize(mySyncSize);
@@ -382,13 +389,15 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
private PersistedJpaSearchFirstPageBundleProvider submitSearch(IDao theCallingDao, SearchParameterMap theParams, String theResourceType, RequestDetails theRequestDetails, String theSearchUuid, ISearchBuilder theSb, String theQueryString, RequestPartitionId theRequestPartitionId) {
StopWatch w = new StopWatch();
Search search = new Search();
+ //TODO GGG MOVE THIS POPULATE AND ALSO THE HOOK CALL HIGHER UP IN THE STACK.
populateSearchEntity(theParams, theResourceType, theSearchUuid, theQueryString, search, theRequestPartitionId);
// Interceptor call: STORAGE_PRESEARCH_REGISTERED
HookParams params = new HookParams()
.add(ICachedSearchDetails.class, search)
.add(RequestDetails.class, theRequestDetails)
- .addIfMatchesType(ServletRequestDetails.class, theRequestDetails);
+ .addIfMatchesType(ServletRequestDetails.class, theRequestDetails)
+ .add(SearchParameterMap.class, theParams);
JpaInterceptorBroadcaster.doCallHooks(myInterceptorBroadcaster, theRequestDetails, Pointcut.STORAGE_PRESEARCH_REGISTERED, params);
SearchTask task = new SearchTask(search, theCallingDao, theParams, theResourceType, theRequestDetails, theRequestPartitionId);
diff --git a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/config/MdmConsumerConfig.java b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/config/MdmConsumerConfig.java
index 204b27e69f1..3ebb0dc6f4c 100644
--- a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/config/MdmConsumerConfig.java
+++ b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/config/MdmConsumerConfig.java
@@ -21,6 +21,7 @@ package ca.uhn.fhir.jpa.mdm.config;
*/
import ca.uhn.fhir.context.FhirContext;
+import ca.uhn.fhir.jpa.interceptor.MdmSearchExpandingInterceptorInterceptor;
import ca.uhn.fhir.jpa.mdm.svc.MdmSurvivorshipSvcImpl;
import ca.uhn.fhir.mdm.api.IMdmControllerSvc;
import ca.uhn.fhir.mdm.api.IMdmExpungeSvc;
@@ -79,6 +80,11 @@ public class MdmConsumerConfig {
return new MdmStorageInterceptor();
}
+ @Bean
+ MdmSearchExpandingInterceptorInterceptor myMdmSearchExpandingInterceptorInterceptor() {
+ return new MdmSearchExpandingInterceptorInterceptor();
+ }
+
@Bean
IMdmSurvivorshipService mdmSurvivorshipService() { return new MdmSurvivorshipSvcImpl(); }
diff --git a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/interceptor/MdmSubmitterInterceptorLoader.java b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/interceptor/MdmSubmitterInterceptorLoader.java
index b3396377031..5d9360bb62d 100644
--- a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/interceptor/MdmSubmitterInterceptorLoader.java
+++ b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/interceptor/MdmSubmitterInterceptorLoader.java
@@ -20,6 +20,7 @@ package ca.uhn.fhir.jpa.mdm.interceptor;
* #L%
*/
+import ca.uhn.fhir.jpa.interceptor.MdmSearchExpandingInterceptorInterceptor;
import ca.uhn.fhir.mdm.api.IMdmSettings;
import ca.uhn.fhir.mdm.log.Logs;
import ca.uhn.fhir.interceptor.api.IInterceptorService;
@@ -41,6 +42,8 @@ public class MdmSubmitterInterceptorLoader {
@Autowired
private IMdmStorageInterceptor myIMdmStorageInterceptor;
@Autowired
+ private MdmSearchExpandingInterceptorInterceptor myMdmSearchExpandingInterceptorInterceptor;
+ @Autowired
private IInterceptorService myInterceptorService;
@Autowired
private SubscriptionSubmitInterceptorLoader mySubscriptionSubmitInterceptorLoader;
@@ -53,6 +56,7 @@ public class MdmSubmitterInterceptorLoader {
myDaoConfig.addSupportedSubscriptionType(Subscription.SubscriptionChannelType.MESSAGE);
myInterceptorService.registerInterceptor(myIMdmStorageInterceptor);
+ myInterceptorService.registerInterceptor(myMdmSearchExpandingInterceptorInterceptor);
ourLog.info("MDM interceptor registered");
// We need to call SubscriptionSubmitInterceptorLoader.start() again in case there were no subscription types the first time it was called.
mySubscriptionSubmitInterceptorLoader.start();
diff --git a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/BaseMdmR4Test.java b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/BaseMdmR4Test.java
index 3c1b28764fa..dae0782cccb 100644
--- a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/BaseMdmR4Test.java
+++ b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/BaseMdmR4Test.java
@@ -44,6 +44,7 @@ import org.hl7.fhir.r4.model.CodeableConcept;
import org.hl7.fhir.r4.model.ContactPoint;
import org.hl7.fhir.r4.model.DateType;
import org.hl7.fhir.r4.model.Medication;
+import org.hl7.fhir.r4.model.Observation;
import org.hl7.fhir.r4.model.Organization;
import org.hl7.fhir.r4.model.Patient;
import org.hl7.fhir.r4.model.Practitioner;
@@ -96,6 +97,8 @@ abstract public class BaseMdmR4Test extends BaseJpaR4Test {
@Autowired
protected IFhirResourceDao myPractitionerDao;
@Autowired
+ protected IFhirResourceDao myObservationDao;
+ @Autowired
protected MdmResourceMatcherSvc myMdmResourceMatcherSvc;
@Autowired
protected IMdmLinkDao myMdmLinkDao;
diff --git a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/interceptor/MdmStorageInterceptorIT.java b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/interceptor/MdmStorageInterceptorIT.java
index 5ad4b9ebe84..051bf27c546 100644
--- a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/interceptor/MdmStorageInterceptorIT.java
+++ b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/interceptor/MdmStorageInterceptorIT.java
@@ -6,10 +6,12 @@ import ca.uhn.fhir.jpa.entity.MdmLink;
import ca.uhn.fhir.jpa.mdm.BaseMdmR4Test;
import ca.uhn.fhir.jpa.mdm.helper.MdmHelperConfig;
import ca.uhn.fhir.jpa.mdm.helper.MdmHelperR4;
+import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.mdm.model.CanonicalEID;
import ca.uhn.fhir.mdm.rules.config.MdmSettings;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
+import ca.uhn.fhir.rest.param.ReferenceParam;
import ca.uhn.fhir.rest.server.TransactionLogMessages;
import ca.uhn.fhir.rest.server.exceptions.ForbiddenOperationException;
import org.hl7.fhir.instance.model.api.IAnyResource;
@@ -65,6 +67,13 @@ public class MdmStorageInterceptorIT extends BaseMdmR4Test {
assertLinkCount(1);
}
+ @Test
+ public void testSearchExpandingInterceptorWorks() {
+ SearchParameterMap subject = new SearchParameterMap("subject", new ReferenceParam("Patient/123").setMdmExpand(true)).setLoadSynchronous(false);
+ myObservationDao.search(subject);
+ }
+
+
@Test
public void testDeleteGoldenResourceDeletesLinks() throws InterruptedException {
myMdmHelper.createWithLatch(buildPaulPatient());
diff --git a/hapi-fhir-jpaserver-test-utilities/src/main/java/ca/uhn/fhir/jpa/config/TestJpaR4Config.java b/hapi-fhir-jpaserver-test-utilities/src/main/java/ca/uhn/fhir/jpa/config/TestJpaR4Config.java
index d5c08620370..1716e099cad 100644
--- a/hapi-fhir-jpaserver-test-utilities/src/main/java/ca/uhn/fhir/jpa/config/TestJpaR4Config.java
+++ b/hapi-fhir-jpaserver-test-utilities/src/main/java/ca/uhn/fhir/jpa/config/TestJpaR4Config.java
@@ -68,7 +68,6 @@ public class TestJpaR4Config extends BaseJavaConfigR4 {
retVal.setDriver(new org.h2.Driver());
retVal.setUrl("jdbc:h2:mem:testdb_r4");
-// retVal.setUrl("jdbc:h2:file:/home/tadgh/smile/hapi-fhir/testdb_r4.db");
retVal.setMaxWaitMillis(10000);
retVal.setUsername("");
retVal.setPassword("");