WIP interceptor using reference param modifier
This commit is contained in:
parent
e6cfb77c79
commit
9f13225aa5
|
@ -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"
|
||||
),
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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(); }
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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("");
|
||||
|
|
Loading…
Reference in New Issue