WIP interceptor using reference param modifier

This commit is contained in:
Tadgh 2021-03-26 17:57:38 -04:00
parent e6cfb77c79
commit 9f13225aa5
11 changed files with 72 additions and 39 deletions

View File

@ -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.
* </li>
* <li>
* ca.uhn.fhir.jpa.searchparam.SearchParameterMap - Contains the details of the search being checked. This can be modified.
* </li>
* </ul>
* <p>
* Hooks should return <code>void</code>.
@ -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"
),
/**

View File

@ -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;

View File

@ -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;

View File

@ -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() {

View File

@ -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<String, String[]> 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<RuntimeSearchParam> 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<List<IQueryParameterType>> lists = theSearchParameterMap.get(patientSearchParam.getName());
for (List<IQueryParameterType> list : lists) {
List<IQueryParameterType> 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<String> 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());
});
}
}

View File

@ -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);

View File

@ -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(); }

View File

@ -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();

View File

@ -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<Practitioner> myPractitionerDao;
@Autowired
protected IFhirResourceDao<Observation> myObservationDao;
@Autowired
protected MdmResourceMatcherSvc myMdmResourceMatcherSvc;
@Autowired
protected IMdmLinkDao myMdmLinkDao;

View File

@ -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());

View File

@ -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("");