This commit is contained in:
juan.marchionatto 2024-08-07 09:36:40 -04:00
parent 801b8b494b
commit 09e561740a
5 changed files with 188 additions and 7 deletions

View File

@ -0,0 +1,79 @@
package ca.uhn.fhir.jpa.searchparam.util;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.util.ISearchParamRegistry;
import ca.uhn.fhir.util.UrlUtil;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import static org.apache.commons.lang3.StringUtils.isBlank;
public class IncludeAndRevIncludeParamHelper {
private final FhirContext myContext;
private final ISearchParamRegistry mySearchParamRegistry;
public IncludeAndRevIncludeParamHelper(FhirContext theFhirContext, ISearchParamRegistry theSearchParamRegistry) {
myContext = theFhirContext;
mySearchParamRegistry = theSearchParamRegistry;
}
public void validateIncludeAndRevIncludeParams(SearchParameterMap theParams) {
validateIncludes(theParams.getIncludes(), Constants.PARAM_INCLUDE);
validateIncludes(theParams.getRevIncludes(), Constants.PARAM_REVINCLUDE);
}
private void validateIncludes(Set<Include> includes, String name) {
for (Include next : includes) {
String value = next.getValue();
if (value.equals(Constants.INCLUDE_STAR) || isBlank(value)) {
continue;
}
String paramType = next.getParamType();
String paramName = next.getParamName();
if (isBlank(paramType) || isBlank(paramName)) {
String msg = myContext
.getLocalizer()
.getMessageSanitized(IncludeAndRevIncludeParamHelper.class, "invalidInclude", name, value, "");
throw new InvalidRequestException(Msg.code(2018) + msg);
}
if (!Constants.INCLUDE_STAR.equals(paramName)
&& mySearchParamRegistry.getActiveSearchParam(paramType, paramName) == null) {
List<String> validNames = mySearchParamRegistry.getActiveSearchParams(paramType).values().stream()
.filter(t -> t.getParamType() == RestSearchParameterTypeEnum.REFERENCE)
.map(t -> UrlUtil.sanitizeUrlPart(t.getName()))
.sorted()
.collect(Collectors.toList());
String searchParamMessage = myContext
.getLocalizer()
.getMessage(
IncludeAndRevIncludeParamHelper.class,
"invalidSearchParameter",
UrlUtil.sanitizeUrlPart(paramName),
UrlUtil.sanitizeUrlPart(paramType),
validNames);
String msg = myContext
.getLocalizer()
.getMessage(
IncludeAndRevIncludeParamHelper.class,
"invalidInclude",
UrlUtil.sanitizeUrlPart(name),
UrlUtil.sanitizeUrlPart(value),
searchParamMessage); // last param is pre-sanitized
throw new InvalidRequestException(Msg.code(2015) + msg);
}
}
}
}

View File

@ -22,6 +22,7 @@ import ca.uhn.fhir.rest.server.util.FhirContextSearchParamRegistry;
import ca.uhn.fhir.test.utilities.ITestDataBuilder;
import ca.uhn.fhir.util.HapiExtensions;
import com.google.common.collect.Sets;
import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.r4.model.BooleanType;
@ -62,6 +63,41 @@ public class SearchParamExtractorR4Test implements ITestDataBuilder {
private final PartitionSettings myPartitionSettings = new PartitionSettings();
final StorageSettings myStorageSettings = new StorageSettings();
@Test
void testLinkExtraction() {
// given
Observation o = ourCtx.newJsonParser().parseResource(Observation.class, """
{
"resourceType": "Observation",
"id": "123",
"subject": {
"identifier": {
"system": "https://example.org/mrn",
"value": "12345"
}
},
"performer": [{
"identifier": {
"system": "https://example.org/mrn",
"value": "12345"
}
}]
}
""");
SearchParamExtractorR4 extractor = new SearchParamExtractorR4(new StorageSettings(), new PartitionSettings(), ourCtx, mySearchParamRegistry);
RuntimeSearchParam activeSearchParam = mySearchParamRegistry.getActiveSearchParam("Observation", "performer:Practitioner");
List<IBase> elements = extractor.extractValues(activeSearchParam.getPath(), o);
//ISearchParamExtractor.SearchParamSet<PathAndRef> pathAndRefs = extractor.extractResourceLinks(o, true);
for (IBase element : elements) {
System.out.println(ourCtx.newJsonParser().encodeToString(element));
}
//System.out.println(pathAndRefs);
}
@Test
public void testParamWithOrInPath() {
Observation obs = new Observation();

View File

@ -183,10 +183,12 @@ public abstract class BaseRestServerHelper {
public abstract boolean registerInterceptor(Object theInterceptorAdapter);
public abstract IResourceProvider getObservationResourceProvider();
public abstract IResourceProvider getEncounterResourceProvider();
public abstract IResourceProvider getPatientResourceProvider();
public abstract IResourceProvider getConceptMapResourceProvider();
public abstract IResourceProvider getPractitionerResourceProvider();
public abstract IIdType createPatientWithId(String theId);

View File

@ -35,9 +35,11 @@ import ca.uhn.test.concurrency.IPointcutLatch;
import ca.uhn.test.concurrency.PointcutLatch;
import jakarta.servlet.ServletException;
import org.hl7.fhir.dstu3.model.ConceptMap;
import org.hl7.fhir.dstu3.model.Encounter;
import org.hl7.fhir.dstu3.model.Observation;
import org.hl7.fhir.dstu3.model.Organization;
import org.hl7.fhir.dstu3.model.Patient;
import org.hl7.fhir.dstu3.model.Practitioner;
import org.hl7.fhir.dstu3.model.Reference;
import org.hl7.fhir.instance.model.api.IBaseBundle;
import org.hl7.fhir.instance.model.api.IBaseResource;
@ -238,8 +240,10 @@ public class RestServerDstu3Helper extends BaseRestServerHelper implements IPoin
private boolean myFailNextPut;
private HashMapResourceProvider<Patient> myPatientResourceProvider;
private HashMapResourceProvider<Observation> myObservationResourceProvider;
private HashMapResourceProvider<Encounter> myEncounterResourceProvider;
private HashMapResourceProvider<Organization> myOrganizationResourceProvider;
private HashMapResourceProvider<ConceptMap> myConceptMapResourceProvider;
private HashMapResourceProvider<Practitioner> myPractitionerResourceProvider;
private MyPlainProvider myPlainProvider;
private final boolean myInitialTransactionLatchEnabled;
@ -304,6 +308,10 @@ public class RestServerDstu3Helper extends BaseRestServerHelper implements IPoin
return myConceptMapResourceProvider;
}
public HashMapResourceProvider<Practitioner> getPractitionerResourceProvider() {
return myPractitionerResourceProvider;
}
public HashMapResourceProvider<Patient> getPatientResourceProvider() {
return myPatientResourceProvider;
}
@ -313,13 +321,13 @@ public class RestServerDstu3Helper extends BaseRestServerHelper implements IPoin
super.initialize();
FhirContext fhirContext = getFhirContext();
myPatientResourceProvider = new MyHashMapResourceProvider(fhirContext, Patient.class);
myPatientResourceProvider = new MyHashMapResourceProvider<>(fhirContext, Patient.class);
registerProvider(myPatientResourceProvider);
myObservationResourceProvider = new MyHashMapResourceProvider(fhirContext, Observation.class);
myObservationResourceProvider = new MyHashMapResourceProvider<>(fhirContext, Observation.class);
registerProvider(myObservationResourceProvider);
myOrganizationResourceProvider = new MyHashMapResourceProvider(fhirContext, Organization.class);
myOrganizationResourceProvider = new MyHashMapResourceProvider<>(fhirContext, Organization.class);
registerProvider(myOrganizationResourceProvider);
myConceptMapResourceProvider = new MyHashMapResourceProvider(fhirContext, ConceptMap.class);
myConceptMapResourceProvider = new MyHashMapResourceProvider<>(fhirContext, ConceptMap.class);
registerProvider(myConceptMapResourceProvider);
myPlainProvider = new MyPlainProvider(myInitialTransactionLatchEnabled);
@ -327,7 +335,7 @@ public class RestServerDstu3Helper extends BaseRestServerHelper implements IPoin
}
public void setConceptMapResourceProvider(HashMapResourceProvider<ConceptMap> theResourceProvider) {
myConceptMapResourceProvider.getStoredResources().forEach(c -> theResourceProvider.store(c));
myConceptMapResourceProvider.getStoredResources().forEach(theResourceProvider::store);
unregisterProvider(myConceptMapResourceProvider);
registerProvider(theResourceProvider);
@ -355,6 +363,11 @@ public class RestServerDstu3Helper extends BaseRestServerHelper implements IPoin
return myRestServer.getObservationResourceProvider();
}
@Override
public IResourceProvider getEncounterResourceProvider() {
return myRestServer.myEncounterResourceProvider;
}
@Override
public HashMapResourceProvider<Patient> getPatientResourceProvider() {
return myRestServer.getPatientResourceProvider();
@ -365,6 +378,11 @@ public class RestServerDstu3Helper extends BaseRestServerHelper implements IPoin
return myRestServer.getConceptMapResourceProvider();
}
@Override
public IResourceProvider getPractitionerResourceProvider() {
return myRestServer.getPractitionerResourceProvider();
}
@Override
public IIdType createPatientWithId(String theId) {
Patient patient = new Patient();

View File

@ -43,9 +43,11 @@ import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.r4.model.Bundle;
import org.hl7.fhir.r4.model.ConceptMap;
import org.hl7.fhir.r4.model.Encounter;
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;
import org.hl7.fhir.r4.model.Reference;
import org.junit.jupiter.api.extension.AfterEachCallback;
import org.junit.jupiter.api.extension.BeforeEachCallback;
@ -203,6 +205,15 @@ public class RestServerR4Helper extends BaseRestServerHelper implements BeforeEa
myRestServer.setObservationResourceProvider(theResourceProvider);
}
@Override
public HashMapResourceProvider<Encounter> getEncounterResourceProvider() {
return myRestServer.getEncounterResourceProvider();
}
public void setEncounterResourceProvider(HashMapResourceProvider<Encounter> theResourceProvider) {
myRestServer.setEncounterResourceProvider(theResourceProvider);
}
@Override
public HashMapResourceProvider<Patient> getPatientResourceProvider() {
return myRestServer.getPatientResourceProvider();
@ -221,10 +232,16 @@ public class RestServerR4Helper extends BaseRestServerHelper implements BeforeEa
myRestServer.setConceptMapResourceProvider(theResourceProvider);
}
public void setPagingProvider(IPagingProvider thePagingProvider) {
myPagingProvider = thePagingProvider;
@Override
public HashMapResourceProvider<Practitioner> getPractitionerResourceProvider() {
return myRestServer.getPractitionerResourceProvider();
}
public void setPractitionerResourceProvider(HashMapResourceProvider<Practitioner> theResourceProvider) {
myRestServer.setPractitionerResourceProvider(theResourceProvider);
}
@Override
public IIdType createPatientWithId(String theId) {
Patient patient = new Patient();
@ -291,8 +308,10 @@ public class RestServerR4Helper extends BaseRestServerHelper implements BeforeEa
private boolean myFailNextPut;
private HashMapResourceProvider<Patient> myPatientResourceProvider;
private HashMapResourceProvider<Observation> myObservationResourceProvider;
private HashMapResourceProvider<Encounter> myEncounterResourceProvider;
private HashMapResourceProvider<Organization> myOrganizationResourceProvider;
private HashMapResourceProvider<ConceptMap> myConceptMapResourceProvider;
private HashMapResourceProvider<Practitioner> myPractitionerResourceProvider;
private RestServerDstu3Helper.MyPlainProvider myPlainProvider;
private final boolean myInitialTransactionLatchEnabled;
@ -407,6 +426,17 @@ public class RestServerR4Helper extends BaseRestServerHelper implements BeforeEa
myObservationResourceProvider = theResourceProvider;
}
public HashMapResourceProvider<Encounter> getEncounterResourceProvider() {
return myEncounterResourceProvider;
}
public void setEncounterResourceProvider(HashMapResourceProvider<Encounter> theResourceProvider) {
myEncounterResourceProvider.getStoredResources().forEach(theResourceProvider::store);
unregisterProvider(myEncounterResourceProvider);
registerProvider(theResourceProvider);
myEncounterResourceProvider = theResourceProvider;
}
public HashMapResourceProvider<Organization> getOrganizationResourceProvider() {
return myOrganizationResourceProvider;
}
@ -423,6 +453,18 @@ public class RestServerR4Helper extends BaseRestServerHelper implements BeforeEa
myConceptMapResourceProvider = theResourceProvider;
}
public HashMapResourceProvider<Practitioner> getPractitionerResourceProvider() {
return myPractitionerResourceProvider;
}
public void setPractitionerResourceProvider(HashMapResourceProvider<Practitioner> theResourceProvider) {
myPractitionerResourceProvider.getStoredResources().forEach(theResourceProvider::store);
unregisterProvider(myPractitionerResourceProvider);
registerProvider(theResourceProvider);
myPractitionerResourceProvider = theResourceProvider;
}
public HashMapResourceProvider<Patient> getPatientResourceProvider() {
return myPatientResourceProvider;
}
@ -436,10 +478,14 @@ public class RestServerR4Helper extends BaseRestServerHelper implements BeforeEa
registerProvider(myPatientResourceProvider);
myObservationResourceProvider = new MyHashMapResourceProvider<>(fhirContext, Observation.class);
registerProvider(myObservationResourceProvider);
myEncounterResourceProvider = new MyHashMapResourceProvider<>(fhirContext, Encounter.class);
registerProvider(myEncounterResourceProvider);
myOrganizationResourceProvider = new MyHashMapResourceProvider<>(fhirContext, Organization.class);
registerProvider(myOrganizationResourceProvider);
myConceptMapResourceProvider = new MyHashMapResourceProvider<>(fhirContext, ConceptMap.class);
registerProvider(myConceptMapResourceProvider);
myPractitionerResourceProvider = new MyHashMapResourceProvider<>(fhirContext, Practitioner.class);
registerProvider(myPractitionerResourceProvider);
myPlainProvider = new RestServerDstu3Helper.MyPlainProvider(myInitialTransactionLatchEnabled);
registerProvider(myPlainProvider);