* (#5442) fetch should also resolve canonical URL references * (#5442) - added test * (#5442) - cleanup? * (#5442) - changelog and reorganize test * (#5442) PR feedback * (#5442) PR feedback * (#5442) cleared ValidatorResourceFetcher linter warnings * (#5442) - new error code * (#5442) caught additional error * (#5442) spotless apply * (#5442) spotless apply --------- Co-authored-by: taha.attari@smilecdr.com <taha.attari@smilecdr.com>
This commit is contained in:
parent
83bfa817ae
commit
63eed3936b
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
type: add
|
||||
issue: 5442
|
||||
title: "The ValidatorResourceFetcher will now resolve canonical URL references as well as simple local references."
|
|
@ -327,18 +327,29 @@ public interface IFhirResourceDao<T extends IBaseResource> extends IDao {
|
|||
|
||||
/**
|
||||
* @deprecated Use {@link #search(SearchParameterMap, RequestDetails)} instead
|
||||
* @throws InvalidRequestException If a SearchParameter is not known to the server
|
||||
*/
|
||||
IBundleProvider search(SearchParameterMap theParams);
|
||||
IBundleProvider search(SearchParameterMap theParams) throws InvalidRequestException;
|
||||
|
||||
IBundleProvider search(SearchParameterMap theParams, RequestDetails theRequestDetails);
|
||||
/**
|
||||
* *
|
||||
* @throws InvalidRequestException If a SearchParameter is not known to the server
|
||||
*/
|
||||
IBundleProvider search(SearchParameterMap theParams, RequestDetails theRequestDetails)
|
||||
throws InvalidRequestException;
|
||||
|
||||
/**
|
||||
* *
|
||||
* @throws InvalidRequestException If a SearchParameter is not known to the server
|
||||
*/
|
||||
IBundleProvider search(
|
||||
SearchParameterMap theParams, RequestDetails theRequestDetails, HttpServletResponse theServletResponse);
|
||||
SearchParameterMap theParams, RequestDetails theRequestDetails, HttpServletResponse theServletResponse)
|
||||
throws InvalidRequestException;
|
||||
|
||||
/**
|
||||
* Search for IDs for processing a match URLs, etc.
|
||||
*/
|
||||
default <T extends IResourcePersistentId> List<T> searchForIds(
|
||||
default <PT extends IResourcePersistentId> List<PT> searchForIds(
|
||||
SearchParameterMap theParams, RequestDetails theRequest) {
|
||||
return searchForIds(theParams, theRequest, null);
|
||||
}
|
||||
|
@ -350,7 +361,7 @@ public interface IFhirResourceDao<T extends IBaseResource> extends IDao {
|
|||
* create/update, this is the resource being searched for
|
||||
* @since 5.5.0
|
||||
*/
|
||||
default <T extends IResourcePersistentId> List<T> searchForIds(
|
||||
default <PT extends IResourcePersistentId> List<PT> searchForIds(
|
||||
SearchParameterMap theParams,
|
||||
RequestDetails theRequest,
|
||||
@Nullable IBaseResource theConditionalOperationTargetOrNull) {
|
||||
|
|
|
@ -24,12 +24,14 @@ import ca.uhn.fhir.context.support.IValidationSupport;
|
|||
import ca.uhn.fhir.i18n.Msg;
|
||||
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.param.TokenParam;
|
||||
import ca.uhn.fhir.rest.param.UriParam;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||
import org.hl7.fhir.common.hapi.validation.validator.VersionSpecificWorkerContextWrapper;
|
||||
import org.hl7.fhir.exceptions.DefinitionException;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.exceptions.FHIRFormatError;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r4.model.IdType;
|
||||
import org.hl7.fhir.r5.elementmodel.Element;
|
||||
|
@ -37,12 +39,11 @@ import org.hl7.fhir.r5.elementmodel.JsonParser;
|
|||
import org.hl7.fhir.r5.model.CanonicalResource;
|
||||
import org.hl7.fhir.r5.utils.validation.IResourceValidator;
|
||||
import org.hl7.fhir.r5.utils.validation.IValidatorResourceFetcher;
|
||||
import org.hl7.fhir.utilities.CanonicalPair;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public class ValidatorResourceFetcher implements IValidatorResourceFetcher {
|
||||
|
@ -50,22 +51,19 @@ public class ValidatorResourceFetcher implements IValidatorResourceFetcher {
|
|||
private static final Logger ourLog = LoggerFactory.getLogger(ValidatorResourceFetcher.class);
|
||||
|
||||
private final FhirContext myFhirContext;
|
||||
private final IValidationSupport myValidationSupport;
|
||||
private final DaoRegistry myDaoRegistry;
|
||||
private final VersionSpecificWorkerContextWrapper myVersionSpecificContextWrapper;
|
||||
|
||||
public ValidatorResourceFetcher(
|
||||
FhirContext theFhirContext, IValidationSupport theValidationSupport, DaoRegistry theDaoRegistry) {
|
||||
myFhirContext = theFhirContext;
|
||||
myValidationSupport = theValidationSupport;
|
||||
myDaoRegistry = theDaoRegistry;
|
||||
myVersionSpecificContextWrapper =
|
||||
VersionSpecificWorkerContextWrapper.newVersionSpecificWorkerContextWrapper(myValidationSupport);
|
||||
VersionSpecificWorkerContextWrapper.newVersionSpecificWorkerContextWrapper(theValidationSupport);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Element fetch(IResourceValidator iResourceValidator, Object appContext, String theUrl)
|
||||
throws FHIRFormatError, DefinitionException, FHIRException, IOException {
|
||||
public Element fetch(IResourceValidator iResourceValidator, Object appContext, String theUrl) throws FHIRException {
|
||||
IdType id = new IdType(theUrl);
|
||||
String resourceType = id.getResourceType();
|
||||
IFhirResourceDao<?> dao = myDaoRegistry.getResourceDao(resourceType);
|
||||
|
@ -74,9 +72,13 @@ public class ValidatorResourceFetcher implements IValidatorResourceFetcher {
|
|||
target = dao.read(id, (RequestDetails) appContext);
|
||||
} catch (ResourceNotFoundException e) {
|
||||
ourLog.info("Failed to resolve local reference: {}", theUrl);
|
||||
return null;
|
||||
try {
|
||||
target = fetchByUrl(theUrl, dao, (RequestDetails) appContext);
|
||||
} catch (ResourceNotFoundException e2) {
|
||||
ourLog.info("Failed to find resource by URL: {}", theUrl);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
return new JsonParser(myVersionSpecificContextWrapper)
|
||||
.parse(myFhirContext.newJsonParser().encodeResourceToString(target), resourceType);
|
||||
|
@ -85,15 +87,40 @@ public class ValidatorResourceFetcher implements IValidatorResourceFetcher {
|
|||
}
|
||||
}
|
||||
|
||||
private IBaseResource fetchByUrl(String url, IFhirResourceDao<?> dao, RequestDetails requestDetails)
|
||||
throws ResourceNotFoundException {
|
||||
CanonicalPair pair = new CanonicalPair(url);
|
||||
SearchParameterMap searchParameterMap = new SearchParameterMap();
|
||||
searchParameterMap.add("url", new UriParam(pair.getUrl()));
|
||||
String version = pair.getVersion();
|
||||
if (version != null && !version.isEmpty()) {
|
||||
searchParameterMap.add("version", new TokenParam(version));
|
||||
}
|
||||
List<IBaseResource> results = null;
|
||||
try {
|
||||
results = dao.search(searchParameterMap, requestDetails).getAllResources();
|
||||
} catch (InvalidRequestException e) {
|
||||
ourLog.info("Resource does not support 'url' or 'version' Search Parameters");
|
||||
}
|
||||
if (results != null && results.size() > 0) {
|
||||
if (results.size() > 1) {
|
||||
ourLog.warn(
|
||||
String.format("Multiple results found for URL '%s', only the first will be considered.", url));
|
||||
}
|
||||
return results.get(0);
|
||||
} else {
|
||||
throw new ResourceNotFoundException(Msg.code(2444) + "Failed to find resource by URL: " + url);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean resolveURL(
|
||||
IResourceValidator iResourceValidator, Object o, String s, String s1, String s2, boolean isCanonical)
|
||||
throws IOException, FHIRException {
|
||||
IResourceValidator iResourceValidator, Object o, String s, String s1, String s2, boolean isCanonical) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] fetchRaw(IResourceValidator iResourceValidator, String s) throws MalformedURLException, IOException {
|
||||
public byte[] fetchRaw(IResourceValidator iResourceValidator, String s) throws UnsupportedOperationException {
|
||||
throw new UnsupportedOperationException(Msg.code(577));
|
||||
}
|
||||
|
||||
|
@ -104,8 +131,7 @@ public class ValidatorResourceFetcher implements IValidatorResourceFetcher {
|
|||
}
|
||||
|
||||
@Override
|
||||
public CanonicalResource fetchCanonicalResource(IResourceValidator iResourceValidator, String s)
|
||||
throws URISyntaxException {
|
||||
public CanonicalResource fetchCanonicalResource(IResourceValidator iResourceValidator, String s) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
package ca.uhn.fhir.jpa.validation;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.support.DefaultProfileValidationSupport;
|
||||
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
|
||||
import ca.uhn.fhir.rest.server.SimpleBundleProvider;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||
import ca.uhn.fhir.test.BaseTest;
|
||||
import ca.uhn.fhir.util.ClasspathUtil;
|
||||
import org.hl7.fhir.common.hapi.validation.validator.FhirInstanceValidator;
|
||||
import org.hl7.fhir.common.hapi.validation.validator.VersionSpecificWorkerContextWrapper;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r5.elementmodel.Element;
|
||||
import org.hl7.fhir.r5.utils.XVerExtensionManager;
|
||||
import org.hl7.fhir.validation.instance.InstanceValidator;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
|
||||
public class ValidatorResourceFetcherTest extends BaseTest {
|
||||
private static final FhirContext ourCtx = FhirContext.forR4();
|
||||
private static final DefaultProfileValidationSupport myDefaultValidationSupport = new DefaultProfileValidationSupport(ourCtx);
|
||||
private static ValidatorResourceFetcher fetcher;
|
||||
private static DaoRegistry mockDaoRegistry;
|
||||
private static IFhirResourceDao<IBaseResource> mockResourceDao;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@BeforeEach
|
||||
public void before() {
|
||||
mockDaoRegistry = mock(DaoRegistry.class);
|
||||
mockResourceDao = mock(IFhirResourceDao.class);
|
||||
fetcher = new ValidatorResourceFetcher(ourCtx, myDefaultValidationSupport, mockDaoRegistry);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkFetchByUrl() {
|
||||
// setup mocks
|
||||
String resource = ClasspathUtil.loadResource("/q_jon_with_url_version.json");
|
||||
doReturn(mockResourceDao).when(mockDaoRegistry).getResourceDao("Questionnaire");
|
||||
doThrow(new ResourceNotFoundException("Not Found")).when(mockResourceDao).read(any(),any());
|
||||
doReturn(new SimpleBundleProvider(List.of(
|
||||
ourCtx.newJsonParser().parseResource(resource)
|
||||
))).when(mockResourceDao).search(any(),any());
|
||||
VersionSpecificWorkerContextWrapper wrappedWorkerContext = VersionSpecificWorkerContextWrapper.newVersionSpecificWorkerContextWrapper(myDefaultValidationSupport);
|
||||
InstanceValidator v = new InstanceValidator(
|
||||
wrappedWorkerContext,
|
||||
new FhirInstanceValidator.NullEvaluationContext(),
|
||||
new XVerExtensionManager(null));
|
||||
RequestDetails r = new SystemRequestDetails();
|
||||
// test
|
||||
Element returnedResource = fetcher.fetch(v, r,"http://www.test-url-for-questionnaire.com/Questionnaire/test-id|1.0.0");
|
||||
assertNotNull(returnedResource);
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue